I have two buttons on my Netbeans GUI form. One button is starting button, and the other is stopping button. When I press the start button, my code runs good, but when I try to stop then the stop button seems disabled. I cannot press the stop button.
My code starts from the GUI, in which this is my code for starting button
private void jButton2MouseClicked(java.awt.event.MouseEvent evt) {
live p=new live(); //this calls the method of my application
p.livecapture();
}
code for stop button
private void jButton1MouseClicked(java.awt.event.MouseEvent evt) {
mm=2;
}
The following while loop is present in my livecapture() method
while(NewJFrame.mm!=2) {
}
Suggestions:
Make sure your capture loop is off of the event thread.
If on the event thread either move it off or use a Swing Timer.
Give the capture class a state variable that will stop its loop and a setter method that other classes the ability to tell it to stop.
In it's loop, have it check its state variable and if set, stop the loop.
Please read up on and follow Swing naming conventions. Your code does not adhere to them making it hard for outsiders (us!) to read and understand it.
For more help, tell us more about your live class, what it does, what it does when "capturing".
I'm not sure on your situation, but it sounds like you're executing your code from the Event Dispatch Thread (EDT). This is the thread in your program that is responsible for listening to your GUI-generated events (among other things). If your EDT is busy processing the code in the listener for the start button, then it will be blind to any other button presses that happen.
To prevent this, you should make your program multi-threaded. This is a huge topic in any programming language, but here is a simple example of one of the many ways it could be done in Java, using a Swing Worker:
class MyWorker extends SwingWorker<Void, Void> {
public Void doInBackground() {
// The code you want to run
return Void;
}
}
MyWorker thread = new MyWorker();
startButton.addActionListener( new ActionListener() {
public void actionPerformed( ActionEvent e ) {
thread.execute();
}
} );
endButton.addActionListener( new ActionListener() {
public void actionPerformed( ActionEvent e ) {
thread.cancel();
}
} );
Related
Related to my previous question: Call repaint from another class in Java?
I'm new to Java and I've had a look at some tutorials on SwingWorker. Yet, I'm unsure how to implement it with the example code I gave in the previous question.
Can anyone please explain how to use SwingWorker with regards to my code snippet and/or point me towards a decent tutorial? I have looked but I'm not sure I understand yet.
Generally, SwingWorker is used to perform long-running tasks in Swing.
Running long-running tasks on the Event Dispatch Thread (EDT) can cause the GUI to lock up, so one of the things which were done is to use SwingUtilities.invokeLater and invokeAndWait which keeps the GUI responsive by which prioritizing the other AWT events before running the desired task (in the form of a Runnable).
However, the problem with SwingUtilities is that it didn't allow returning data from the the executed Runnable to the original method. This is what SwingWorker was designed to address.
The Java Tutorial has a section on SwingWorker.
Here's an example where a SwingWorker is used to execute a time-consuming task on a separate thread, and displays a message box a second later with the answer.
First off, a class extending SwingWorker will be made:
class AnswerWorker extends SwingWorker<Integer, Integer>
{
protected Integer doInBackground() throws Exception
{
// Do a time-consuming task.
Thread.sleep(1000);
return 42;
}
protected void done()
{
try
{
JOptionPane.showMessageDialog(f, get());
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
The return type of the doInBackground and get methods are specified as the first type of the SwingWorker, and the second type is the type used to return for the publish and process methods, which are not used in this example.
Then, in order to invoke the SwingWorker, the execute method is called. In this example, we'll hook an ActionListener to a JButton to execute the AnswerWorker:
JButton b = new JButton("Answer!");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
new AnswerWorker().execute();
}
});
The above button can be added to a JFrame, and clicked on to get a message box a second later. The following can be used to initialize the GUI for a Swing application:
private void makeGUI()
{
final JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new FlowLayout());
// include: "class AnswerWorker" code here.
// include: "JButton" b code here.
f.getContentPane().add(b);
f.getContentPane().add(new JButton("Nothing"));
f.pack();
f.setVisible(true);
}
Once the application is run, there will be two buttons. One labeled "Answer!" and another "Nothing". When one clicks on the "Answer!" button, nothing will happen at first, but clicking on the "Nothing" button will work and demonstrate that the GUI is responsive.
And, one second later, the result of the AnswerWorker will appear in the message box.
Agree:
Running long-running tasks on the Event Dispatch Thread (EDT) can cause the GUI to lock up.
Do not agree:
so one of the things which were done is to use SwingUtilities.invokeLater and invokeAndWait which keeps the GUI responsive..
invokeLater still runs the code on the EDT, and can freeze your UI!! Try this:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
At least I, cannot move my mouse once I click the button which triggers the actionPerformed with the above code. Am I missing something?
My understanding of the Swing Event Dispatcher Thread (EDT) is that its a dedicated thread where event handling code is executed. So, if my understanding is correct, then in the example below:
private class ButtonClickListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
// START EDT
String command = e.getActionCommand();
if( command.equals( "OK" )) {
statusLabel.setText("Ok Button clicked.");
} else if( command.equals( "Submit" ) ) {
statusLabel.setText("Submit Button clicked.");
} else {
statusLabel.setText("Cancel Button clicked.");
}
// END EDT
}
}
All the code in between START EDT and END EDT is executing on the EDT, and any code outside of it is executing on the main application thread. Similarly, another example:
// OUTSIDE EDT
JFrame mainFrame = new JFrame("Java SWING Examples");
mainFrame.setSize(400,400);
mainFrame.setLayout(new GridLayout(3, 1));
mainFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent){
// START EDT
System.exit(0);
// END EDT
}
// BACK TO BEING OUTSIDE THE EDT
});
Again, only the System.exit(0) is executed inside the EDT.
So for starters, if my understanding of the "division of labor" between EDT and main app thread code execution is incorrect, please begin by correcting me!
Now then, I came across an article that emphasized the use of creating a new Thread from inside all this EDT code, which would make my first example above look like this:
public class LabelUpdater implements Runnable {
private JLabel statusLabel;
private ActionEvent actionEvent;
// ctor omitted here for brevity
#Override
public void run() {
String command = actionEvent.getActionCommand();
if (command.equals( "OK" )) {
statusLabel.setText("Ok Button clicked.");
} else if( command.equals( "Submit" ) ) {
statusLabel.setText("Submit Button clicked.");
} else {
statusLabel.setText("Cancel Button clicked.");
}
}
}
private class ButtonClickListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
// START EDT
Thread thread = new Thread(new LabelUpdater(statusLabel, e));
thread.start();
// END EDT
}
}
My question: what advantage (or lack thereof) is there to this approach? Should I always code my EDT code this way, or is there a rubric one needs to follow as a guidelines for when to apply it? Thanks in advance!
The question is a bit broad and unspecific, but I'll try to address some of the points that you asked about. The entry point for further, own research is probably the Lesson: Concurrency in Swing, although it may indeed be hard to derive definite statements for specific cases from that.
First of all, there is an overarching rule in Swing - referred to as the Single Thread Rule:
Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread.
(Unfortunately, it is no longer stated so clearly in the tutorial)
Keeping that in mind, looking at your snippets:
// OUTSIDE EDT
JFrame mainFrame = new JFrame("Java SWING Examples");
...
This is often true, unfortunately - and unfortunately, even in some of the official Swing examples. But this may already cause problems. To be on the safe side, the GUI (including the main frame) should always be handled on the EDT, using SwingUtilities#invokeLater. The pattern is always the same then:
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
JFrame mainFrame = new JFrame("Java SWING Examples");
...
mainFrame.setVisible(true);
}
Regarding the second example that you showed, involving the LabelUpdater class: I'd be curious from which article you got this. I know, there is a lot of cr4p out there, but this example doesn't even remotely make sense...
public class LabelUpdater implements Runnable {
private JLabel statusLabel;
...
#Override
public void run() {
...
statusLabel.setText("Ok Button clicked.");
}
}
If this code (i.e. the run method) is executed in an new thread, then it obviously violates the single thread rule: The status of the the JLabel is modified from a thread that is not the event dispatch thread!
The main point of starting a new thread in an event handler (e.g. in an actionPerformed method of an ActionListener) is to prevent blocking the user interface. If you had some code like this
someButton.addActionListener(e -> {
doSomeComputationThatTakesFiveMinutes();
someLabel.setText("Finished");
});
then pressing the button would cause the EDT to be blocked for 5 minutes - i.e. the GUI would "freeze", and look like it hung up. In these cases (i.e. when you have long-running computations), you should do the work in an own thread.
The naive approach of doing this manually could (roughly) look like this:
someButton.addActionListener(e -> {
startBackgroundThread();
});
private void startBackgroundThread() {
Thread thread = new Thread(() -> {
doSomeComputationThatTakesFiveMinutes();
someLabel.setText("Finished"); // WARNING - see notes below!
});
thread.start();
}
Now, pressing the button would start a new thread, and the GUI would no longer block. But note the WARNING in the code: Now there's this problem again of the JLabel being modified by a thread that is not the event dispatch thread! So you'd have to pass this back to the EDT:
private void startBackgroundThread() {
Thread thread = new Thread(() -> {
doSomeComputationThatTakesFiveMinutes();
// Do this on the EDT again...
SwingUtilities.invokeLater(() -> {
someLabel.setText("Finished");
});
});
thread.start();
}
This may look clumsy and complicated, and as if you could have a hard time figuring out on which thread you currently are. And that's right. But for the common task of starting a long-running task, there is the SwingWorker class explained in the tutorial that makes this pattern somewhat simpler.
Shameless self-promotion: A while ago, I created a SwingTasks library, which is basically a "Swing Worker on steroids". It allows you to "wire up" methods like this...
SwingTaskExecutors.create(
() -> computeTheResult(),
result -> receiveTheResult(result)
).build().execute();
and takes care of showing a (modal) dialog if the execution takes too long, and offers some other convenience methods, e.g. for showing a progress bar in the dialog and so on. The samples are summarized at https://github.com/javagl/SwingTasks/tree/master/src/test/java/de/javagl/swing/tasks/samples
my problem is that I want to add the same ActionListener to 2 different components on my GUI program. One, when the user presses Enter Key in a JTextField, and the second when the user clicks on a JButton. I am using the Netbeans IDE.
So I created a Thread, t1, and in the actionListener's actionPerformed method, I simply put t1.start(). Then I added the actionListener object to my JTextField and my JButton.
When I run the program, the first time I either click the button or press Enter, the program runs smoothly. But on the second time I click the button or press Enter, the program throws an IllegalStateException.
Here is my code:
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
//Do something
}
});
public final ActionListener listener;
public myClass () { //Constructor
this.listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
t1.start();
}
};
InitComponents();
JButton.addActionListener(listener); //Adding listener object to JButton.
JTextField.addActionListener(listener); //Adding listener object to JTextField.
}
I am thinking that the thread did not 'die' from the first time I clicked or pressed Enter, even though the run() method already exited. I tested the program at different points to make sure that the run() method did exit.
I am able to make program work if I create a thread in both the JButtonActionPerformed( and JTextFieldActionPerformed() methods, and start them inside these methods itself. But it's redundant since I am writing the same actions to be performed in 2 different methods.
Any help on why the IllegalStateException exception was thrown and on how to create a single ActionListener for both the JComponents using a thread is appreciated.
Thanks!
As the JavaDocs state...
It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.
Throws:
IllegalThreadStateException - if the thread was already started.
You can not start a Thread twice. Instead, start with a Runnable and wrap a new Thread around it each time you want to run it
Let's say i have a listener attached to a button. When i press this button, actionPerformed is called and i set a label as visible. Then the calculate() method runs(which has some really long calculations inside it and it takes time). Then i wanna print the results with the show() method.
Thing is that i know for a fact that the label will be set as visible after all the code inside actionPerformed will be executed.
So my question is : How should i set the calculate method to run on background? Threads? SwingTimer? SwingWorker? I haven't found an ideal way yet.
class ButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
calculateLbl.setVisible(true);
calculate();
show();
}
}
Your problem is one of Swing concurrency: When calculate() is called on the Swing event thread, the long-running code hampers the event thread, preventing it from painting to the JLabel. The solution is to run calculate in a background thread, and then be notified when it is done. When notification occurs, call show(). A SwingWorker would work great for this since it comes with its own notification mechanism.
e.g.,
#Override
public void actionPerformed(ActionEvent e) {
calculateLbl.setVisible(true);
new SwingWorker<Void, Void>() {
public Void doInBackground() throws Exception{
calculate(); // this is run in a background thread
// take care that calculate makes no Swing calls
return null;
}
protected void done() {
show(); // this is run on the Swing event thread
}
}.execute();
}
Caveat: code not tested/compiled/nor run.
A problem with the above code is that it does not handle any exceptions that might be thrown within the calculate method, and a cleaner better way to do this is to create a SwingWorker variable, attach a PropertyChangeListener to it, and when its SwingWorker.StateValue is SwingWorker.StateValue.DONE, call get() on the SwingWorker and handle any possible exceptions there.
Related to my previous question: Call repaint from another class in Java?
I'm new to Java and I've had a look at some tutorials on SwingWorker. Yet, I'm unsure how to implement it with the example code I gave in the previous question.
Can anyone please explain how to use SwingWorker with regards to my code snippet and/or point me towards a decent tutorial? I have looked but I'm not sure I understand yet.
Generally, SwingWorker is used to perform long-running tasks in Swing.
Running long-running tasks on the Event Dispatch Thread (EDT) can cause the GUI to lock up, so one of the things which were done is to use SwingUtilities.invokeLater and invokeAndWait which keeps the GUI responsive by which prioritizing the other AWT events before running the desired task (in the form of a Runnable).
However, the problem with SwingUtilities is that it didn't allow returning data from the the executed Runnable to the original method. This is what SwingWorker was designed to address.
The Java Tutorial has a section on SwingWorker.
Here's an example where a SwingWorker is used to execute a time-consuming task on a separate thread, and displays a message box a second later with the answer.
First off, a class extending SwingWorker will be made:
class AnswerWorker extends SwingWorker<Integer, Integer>
{
protected Integer doInBackground() throws Exception
{
// Do a time-consuming task.
Thread.sleep(1000);
return 42;
}
protected void done()
{
try
{
JOptionPane.showMessageDialog(f, get());
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
The return type of the doInBackground and get methods are specified as the first type of the SwingWorker, and the second type is the type used to return for the publish and process methods, which are not used in this example.
Then, in order to invoke the SwingWorker, the execute method is called. In this example, we'll hook an ActionListener to a JButton to execute the AnswerWorker:
JButton b = new JButton("Answer!");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
new AnswerWorker().execute();
}
});
The above button can be added to a JFrame, and clicked on to get a message box a second later. The following can be used to initialize the GUI for a Swing application:
private void makeGUI()
{
final JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new FlowLayout());
// include: "class AnswerWorker" code here.
// include: "JButton" b code here.
f.getContentPane().add(b);
f.getContentPane().add(new JButton("Nothing"));
f.pack();
f.setVisible(true);
}
Once the application is run, there will be two buttons. One labeled "Answer!" and another "Nothing". When one clicks on the "Answer!" button, nothing will happen at first, but clicking on the "Nothing" button will work and demonstrate that the GUI is responsive.
And, one second later, the result of the AnswerWorker will appear in the message box.
Agree:
Running long-running tasks on the Event Dispatch Thread (EDT) can cause the GUI to lock up.
Do not agree:
so one of the things which were done is to use SwingUtilities.invokeLater and invokeAndWait which keeps the GUI responsive..
invokeLater still runs the code on the EDT, and can freeze your UI!! Try this:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
At least I, cannot move my mouse once I click the button which triggers the actionPerformed with the above code. Am I missing something?