I have a dialog containing several buttons. When a particular button is clicked, it's ActionListener iniates a process that takes several seconds to complete. During this time I want to provide some feedback to the user. To take a simple approach, I have a label in the dialog "Computing..." which is initially not visible. A code segment looks like this
button_OpenHoursReport.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
lbl_Computing.setVisible(true);
new runAndRenderReport();
RunAndRenderReport.main(null);
lbl_Computing.setVisible(false);
}
});
The problem is, the lbl_Computing text does not become visible until the RunAndRenderReport is completed. Obviously, that's not much help to the user. Don't know where to go from here. Does this have to do with threads? If so, I could use some guidance on how to get started.
actionPerformed() is executed on the GUI-thread (EDT), so avoid executing intensive operations on it. Instead use SwingWorker.
See How SwingWorker works.
A trick which is much easier than using SwingWorker is to call paintImmediately on your label after calling setVisible(true). You should see the effects - immediately.
lbl_Computing.paintImmediately(0, 0, lbl_Computing.getWidth(), lbl_Computing.getHeight());
But SwingWorker is the way to go if you want your GUI to be responsive in other ways as well while the reporting is running.
Related
I know many people have asked this question before but I couldn't find any answer that solved my problem. My code is like this:
public void mouseClicked(MouseEvent arg0) {
TEXT.setText("ON");
myfunction(); //runs for a very long time
}
The original text of JLabel is "OFF". Now I want to change the text to "ON" when the mouse is clicked but the text doesn't set until myfunction() is complete (which may take several minutes).
I have tried the invalidate function, making a separate function for setting the text but nothing is working.
Please help me with this problem!
The problem is that mouseClicked(...) is executed on the UI Thread. That is the Thread that is responsible for handling all sorts of user actions (like a mouse click) and also the drawing of components (like updating the text of the label on screen). If you execute your long running method call on the UI thread, it will be blocked and can't draw anything until execution is complete. You'll have to use multi threading to get around this problem.
The following might not be the most elegant solution, but if you are new to multi threading it will get the job done:
public void mouseClicked(MouseEvent arg0) {
TEXT.setText("ON");
(new Thread() {
public void run() {
myfunction();
}
}).start();
}
It will spawn a new Thread that handles your method, which will let the UI Thread continue doing its thing. consider deactivating the button that has just been clicked, so the user can't start the execution while it is already in progress (which usually is what you want..)
Inside the actionPerformed method of a jButton, I have the following code:
btnLogin.setText("Logging In...");
btnLogin.setPreferredSize(new Dimension(110, 29));
btnLogin.setEnabled(false);
//more stuff here, irrelevant to this
This works, however it only takes visual effect (is repainted) once the method is complete.
If in the //more stuff here area I have code that takes a long time to complete, the effects of the btnLogin changes do not take effect until that code is complete.
I have tried typing:
this.revalidate();
this.repaint();
Directly after the first 3 lines, and multiple other solutions, to try to force the damn thing to repaint DURING the method, but no matter what, it only happens at the end!
Another thing I've noticed is that if I call a JOptionPane in the middle of the method, the frame WILL repaint (in the background), so that's interesting.
What is is that's automatically happening in the end of the method that I need to call to make it happen during the method?
Thanks in advance!
You're blocking the Swing event thread with the long-running code, and this prevents Swing from drawing the text changes. The solution:
Do the long-running code in a background thread such as in a SwingWorker's doInBackground method.
But make sure to make most all Swing calls on the Swing event thread.
Read the Concurrency in Swing tutorial to learn the details on the Swing event thread and threading issues.
i need to develop java code to have JFrame with a text filed and button.Using Threads,i need to update time for every one minute in the title bar of JFrame.Using Another Thread i need to display textbox value in the console when a button is clicked.I have code for performing both operations (updating time for every min and getting text box value)but i dont know how to add two threads in same class.if anyone knows pls help me out
What you are asking is a dangerous thing to do in Swing. Swing components are not thread-safe and should only be updated from the Event Dispatching Thread (also known as the EDT or Swing Thread). To do this, Swing has utility methods such as SwingUtilities.invokeLater(Runnable) which will execute the code in the Runnable (at some point in the future) on the EDT. The idea is that you place your code to do Swing-things (like update the Title of the JFrame with the time) inside of a separate Runnable and pass it to invokeLater().
To do this, you can create an anonymous Runnable class:
Runnable updateJFrame = new Runnable () {
public void run () {
myJFrame.setTitle("My New Title");
}
};
SwingUtilities.invokeLater(updateJFrame);
Using invokeLater() also ensures that the components get refreshed/repainted properly after they have been updated. (The behavior you are seeing when using statics may actually be a refresh/repaint issue.) The moral of this story is that if you manipulate Swing components on a non-EDT thread, all bets are off.
Having the following szenario: blurring a textBox (input) writes text to my status-Box (in certain conditions), and clicking a button also writes text to the status-Box.
Now when clicking the button it will blur my textBox if it is focused and that will cause the status-Box to flicker as first the blurHandler will write its result and then the clickHandler.
As i want the result of the clickHandler to appear my idea is to let the blurHandler place an event at the end of the queue which checks whether a clickHandler has written a result before.
In Swing I would try SwingUtilities.invokeLater(Runnable).
The equivalent in GWT is said to be the Scheduler but those deferred or finally commands seems always to run after the current event and before the next.
So far i use Scheduler.scheduleFixedDelay with 100ms delay and hope it comes after the clickHanlder in each browser.
See similar problem with answer.
I think there must be a better solution for this.
How to really add an event to the end of the queue or is it impossible due to limitations of HTML?
Try:
Scheduler.get().scheduleDeferred(new Command() {
#Override
public void execute() {
.......
}
});
See
Class Scheduler
In a method of a class, I update the same label twice. The first time, it shows the user message to wait, but the second time shows the user the completed message. Something like the following:
MyClass{
myMethod(){
jLabel.setText("Please wait...");
//does calculation
jLabel.setText("Completed successfully!");
}
}
When I run the app, all I see is the "Completed successfully" message. Is the JLabel updating too quickly? How do I control it? I tried using the following but no luck :(
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jLabel.setText("Please wait...");
}
});
If the calculation is done in the event dispatch thread, then it blocks the thread and prevents it from doing all its repaintings. You must do the computation in another thread, and have this thread change the label text when it ends (in the event dispatch thread, using SwingUtilities.invokeLater, or by using the SwingWorker mechanism). If the computation is really fast, it's not worth it, though, because the second text will appear so quickly after the first one that you won't even notice the first one.
Have a look at SwingWorker, which is designed for such use-cases. Its javadoc contains a useful example.
if you want to delay some Action/Event then use javax.swing.Timer, or wrap your code to the Runnable#Thread,
notice: never use Thread.sleep(int) durring EDT, your GUI freeze until Thread.sleep(int) ended
example for javax.swing.Timer & Runnable#Thread & Freeze GUI by implements Thread.sleep(int) durring EDT here
Possibly because your calculations are happening too fast. Did you try putting a delay after your calc.
Also as Nizet points out above if this is happening in EDT the component will not repaint until end of the thread which means it will take the last set value.