Reputation: 65
I'm new to Swing, and currently trying to develop a simple GUI application in NetBeans.
I want to create some kind of a GUI logging system, to write the current action that's being performed by the application, into a TextArea.
As a simple example, I created a JFrame form which contains only 2 objects: a "Start" button and a TextArea.
When the "Start" button is pressed, it invokes some kind of a lengthy method that should take some time (say, 10 seconds) to complete running, and while this method is running, I want to append text to the TextArea from withing this lengthy method (and of course I want the TextArea to be immediately updated).
My problem is that I cannot find the proper way of doing that. Anyway I tried doing this, when I press on the "Start" button, the application freezes for 10 seconds, without updating the TextArea like I wanted. Only when the method finishes, I see the update to the TextArea.
Here's a sample code:
private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {
try {
for (int i = 0; i < 10; i++) {
textArea.setText(i + "\n");
Thread.sleep(1000);
}
} catch (Exception e) {}
}
In this example what I expect to see is that once I click the button, for the next 10 seconds, a new line would be appended to the TextArea every second, like so:
1
2
3
4
...
But the real result that I get from this code is that the application freezes for 10 seconds, and finally the TextArea is updated and displays only the digit 9.
I've tried many different methods of doing this right, mainly using the SwingUtilities.invokeLater and SwingWorker methods, but none of them worked for me.
Any help with finding the right way of doing that would be greatly appreciated.
Upvotes: 2
Views: 5979
Reputation: 6465
Like stated in other answers, you're going to want to use SwingWorker
- I recommend reading up on it, as it is an incredibly useful tool to have. This implementation should give you what you're looking for in your sample:
Your button's action:
button.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent arg0) {
new Worker().execute();
}
});
Your swing worker:
public class Worker extends SwingWorker<String, String>{
@Override
protected String doInBackground() throws Exception {
//This is what's called in the .execute method
for(int i = 0; i < 10; i++){
//This sends the results to the .process method
publish(String.valueOf(i));
Thread.sleep(1000);
}
return null;
}
protected void process(List<String> item) {
//This updates the UI
textArea.append(item + "\n");
}
}
Upvotes: 6
Reputation: 33534
1. Always keep the UI work on the UI thread, and Non-UI work on the Non-UI thread.
2. In Java GUI applications, main()
method is not long lived, after scheduling the construction of GUI in the Event Dispatcher Thread
, the main() method quits...and Now its EDT's responsibility to handle the GUI.
3. Always keep your EDT thread, which is the GUI thread only for GUI work.
Eg:
public static void main(String[] args){
EventQueue.invokeLater(new Runnable(){
public void run(){
myframe.setVisible(true);
}
}
}
4. Create a separate Non-UI
thread to handle that long time taking method.
5. You can simply use a Thread
or use SwingWorker
which is specially introduced into Java to sync the UI and Non-UI thread.
Upvotes: 8
Reputation: 44240
Use the javax.swing.Timer
class. For more information, see How to Use Swing Timers.
Upvotes: 3