I am writing a desktop application using SWT. What is the simplest way to update GUI controls from another thread?
Use Display.asyncExec or Display.syncExec, depending on your needs.
For example, another thread might call this method to safely update a label:
private static void doUpdate(final Display display, final Label target,
final String value) {
display.asyncExec(new Runnable() {
#Override
public void run() {
if (!target.isDisposed()) {
target.setText(value);
target.getParent().layout();
}
}
});
}
More here
There's a tutorial here.
"SWT does make a point to fail-fast when it comes to threading problems; so at least the typical problems don't go unnoticed until production. The question is, however, what do you do if you need to update a label/button/super-duper-control in SWT from a background thread? Well, it's surprisingly similar to Swing:"
// Code in background thread.
doSomeExpensiveProcessing();
Display.getDefault().asyncExec(new Runnable() {
public void run() {
someSwtLabel.setText("Complete!");
}
});
You can actually just sent a message to the GUI thread that some modification has been changed. This is cleaner if you see it from MVC perspective.
When creating the separate thread from the main thread pass the Gui object to the new thread and u can access all the properties of that GUI object.
Related
All processors that update my swing GUI from places other than by user clicks are performed using EventQueue.invokeLater (for example output generated from a long running background non-EDT thread process).
In my current scenario I have a TCPIP socket read background thread process that returns data which needs to update a JEditorPane object. I use the JEditorPane setText call. The problem is, placing the setText call in an invokeLater routine freezes the GUI for large files (example case test 19,790 KB).
My attempt to resolve this is to perform the setText action in a non-EDT background thread. This appears to solve the problem, BUT, I am concerned about best practices, because JEditorPane setText in java 7 (the JDK I’m using) is NOT thread safe.
HOWEVER trawling through the JDK code, it seems to me that the lengthy process performed here is in JDKs DefaultEditorKit.read, and within that method the only code that would effect the GUI is in the doc.insertString calls (unless I am mistaken). Now when you look at JDKs PlainDocument.java insertString method it documents that IT IS thread safe, so one would think therefore that this solution is sound.
HOWEVER...
Stress testing my application, I do some random clicks around the GUI, and currently have a tree node animation running, and during the large load below, it does appear to slow down the animation a little, hence my concern that I’ve not performed the best resolution (also very concerned about future JREs screwing me up here and therefore not relying on insertString currently being threadsafe).
I’ve investigated and seen that this question “how to handle long running JEditorPane setText” has been asked before but with no suitable answers.
QUESTION 1) Does anyone have thoughts on my current observations?
QUESTION 2) Does anyone have ideas on how I could achieve this another?
NOTE JEditorPane is my only choice here because I will be eventually supporting dynamic fonts of an IDE look and feel nature.
NOTE also that the below call is called within a EventQueue.invokeLater routine, so the initial editorPane work is in the EDT.
public void updateBigDataEditorPane( final JEditorPane editorPane, final String inStr ) {
// Update editor object and content.
editorPane.setContentType( "text/plain" );
editorPane.setFont(new java.awt.Font("Monospaced", 0, 12)); // NOI18N
editorPane.setDocument( editorPane.getEditorKit().createDefaultDocument() );
// Content update. NOTE in non-EDT thread to stop GUI freeze with large content.
new Thread( new Runnable() {
#Override
public void run() {
//// synchronized
synchronized( tabsLock ) {
// Set content.
editorPane.setText( inStr );
} //// synchronized
}
}).start();
}
You could use the EditorPane's Document (via editorPane.getDocument()) and perform the changes to this document (via insertString(...), instead of using setText(...)) in another thread.
By doing this, you can (kind of) dynamically (means: while reading) write the contents.
As Example (add text from file to Textpane, without freezing UI):
(EDIT: this new code is not tested, but it should better demonstrate my suggestion...):
public void readFileAsync()
{
final String fileName = "/path/to/file.txt";
final StyledDocument doc = yourTextPane.getStyledDocument();
Runnable r = new Runnable()
{
public void run()
{
try
{
List<String> lines = Files.readAllLines(Paths.get(fileName), Charset.defaultCharset());
for (String line : lines)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
doc.insertString(doc.getLength(), line, null );
}
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
Thread t = new Thread(r);
t.start();
}
While the answers provided were beneficial, and would be used to address specific long running EDT thread requirements, the solution I ended up using was as follows;
Create a new JEditorPane object
Perform the time consuming setText call
On completion, replace currently active JEditorPane object on the GUI with this newly created one.
Use SwingWorker to perform the background non-EDT tasks (1 & 2), and then perform step 3 on completion on the EDT thread.
I had a problem earlier where I was trying to add objects to my canvas but the SwingUtilities.invokeLater hadn't really done its job yet. I really need to be able to add things reliably to this JPanel but I keep running into this same error. Is there a better alternative to the below code?
private void startNewGame() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
gameFrame = new InvadersGameFrame();
}
});
}
See SwingUtilities.invokeAndWait(Runnable) which:
Causes doRun.run() to be executed synchronously on the AWT event dispatching thread. This call blocks until all pending AWT events have been processed and (then) doRun.run() returns. This method should be used when an application thread needs to update the GUI.
I am using the latest Eclipse, and GWT Designer, to make a swing application in Java.
The main function in my application window (which is a javax.swing.JFrame) in the auto generated by the tools looks like this:
/* launch the application */
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
AppWindow window = new AppWindow();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
This seems like a lot of noise around what could have been just this:
public static void main(String[] args) {
try {
AppWindow window = new AppWindow();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
I have read that the EventQueue.InvokeLater technique is required in some situations, and another question asks where to use it here.
My question is simpler; Why do this automatically in the code generator here? Why should main return quickly and let the application window get created later by the event queue? Wouldn't blocking be exactly the point? Why is the JFrame auto-generated designer doing this EventQueue stuff? I have tried to see some difference in the start up and showing of forms whether this code is done the simpler way or the harder way, and I can only conclude provisionally that this has some benefits that are not visible in tiny demo apps made by beginners like me, and that perhaps in real-world large complex Jframe based classes, there is some benefit to this delaying/queuing strategy?
Depending on your application and how it's being used, it's possible that there could be something that is drawing on the screen (and thus using the EventQueue) before or during the call to your main method. Calls that modify any UI components should be made on the Event Dispatch Thread, and this includes setting the application visible.
So just to be safe, it's a good practice to start your application on the EDT.
Why do this automatically in the code generator here?
It won't hurt, it's easy to generate, and it's considered good practice.
Why should main return quickly and let the application window get created later by the event queue?
It's possible that the main method is being called from some other application that is using the EDT and may have already drawn something on screen. If you draw your application directly in main, it's possible that your application may be altering some component that is in the process of being handled by something on the EDT, and potentially already drawn on the screen.
So just to be safe in case this situation ever happens, you should leave it up to the EDT to draw your application so it can do it when it won't interfere with anything else.
Wouldn't blocking be exactly the point?
Unless something else is calling main other than the JVM process that your user started by double-clicking the desktop icon, it's not going to make a difference when main returns as long as there is something on the screen.
I can only conclude provisionally that this has some benefits that are not visible in tiny demo apps made by beginners like me
You're right - most of the time it's probably not gonna make a difference, but I presume they included it because it was easy to generate & implement, it can't hurt, and it would exemplify good practice.
1) why is building Swing GUI inside try-catch-finally, I can't see any reason(s) for that, split create non thread safe GUI and non thread safe code to the separates threads,
2) Swing isn't thread safe, then correct is in all cases that pack() + setVisible(true) would be
last GUI rellated code lines
wrapped into invokeLater
forgot for examples from some code ExamplesDepots, this forum, another forums, sure these code works, but with risk that whatever/everything could happen
correct Swing GUI launch
for example
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
AppWindow window = new AppWindow();
window.frame.setVisible(true);
}
});
}
3) is there some Serializable, Custom L&F then (better would be) wrap into invokeAndWait
In many Swing snippets given here as answers, there is a call to SwingUtilities#invokeLater from the main method:
public class MyOneClassUiApp {
private constructUi() {
// Some Ui related Code
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MyOneClassUiApp().constructUi();
}
});
}
}
But according to the Threads and Swing article, it is safe to construct UI from main thread:
A few methods are thread-safe: In the Swing API documentation,
thread-safe methods are marked with this text:
This method is thread safe, although most Swing methods are not.
An application's GUI can often be constructed and shown in the main
thread: The following typical code is safe, as long as no components
(Swing or otherwise) have been realized:
public class MyApplication {
public static void main(String[] args) {
JFrame f = new JFrame("Labels");
// Add components to
// the frame here...
f.pack();
f.show();
// Don't do any more GUI work here...
}
}
So, is there a real (thread safety) reason to construct the UI in main through SwingUtilities#invokeLater, or this is just a habit, to remember do it in other cases?
"The Swing single-thread rule: Swing components and models should be created, modified, and queried only from the event-dispatching thread."—Java Concurrency in Practice, also discussed here and here. If you don't follow this rule, then you can't reliably construct, modify or query any component or model that may have assumed that you did follow the rule. A program may appear to work correctly, only to fail mysteriously in a different environment. As violations may be obscure, verify correct usage by using one of the approaches mentioned here.
I think that using SwingUtiltities.invokeLater() is just an easier way to execute some code asynchronously. Sometimes it is required for certain application: for example you can create 2 separate windows simultaneously. Nothing more.
It's safe to create your Swing UI in the main method because how would other components be displayed before you set up your UI? As long as you haven't thrown some stuff on the screen already you'll be fine. In other words, this would be bad:
public class MyApplication
{
public static void main(String[] args)
{
JFrame f = new JFrame("Labels");
// Add components to
// the frame here...
f.pack();
f.show();
// now make another frame:
JFrame f2 = new JFrame("Labels2");
// Add components to the 2nd frame here...
f2.pack();
f2.show();
}
}
If you did the above you'd have JFrame f up and running then you'd be adding Swing UI components off the Event Dispatch Thread (EDT). invokeLater runs the code on the EDT - it won't hurt to use it if you want extra peace of mind.
I have tried a lot, but can't seem to get it to work.
I was told to use EDT with the following example.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Modify the GUI here
}
});
I have read on this topic a lot and still don't understand. I get what a thread is, but the .invokeLater still makes no sense to me. Honestly if you can explain in detail this it would be a big help!
Goal of Program: To get the randomly generated key that is constantly created every second to update itself afterward in the GUI.
So there is an EDT (Event Dispatch Thread). All actions that appear on your screen are executed by the EDT. There is only one EDT per Swing application.
You are in some arbitrary thread and you want to update the GUI through that thread? Well like I said there is only one EDT for each swing application, so you have to tell that EDT to display the label (or whatever context you want).
The idea here, is you push this Runnable onto a queue that the EDT pulls from. Eventually, your runnable will be processed by the EDT when all other actions before it are completed.
I recommend you get the book Filthy Rich Clients. There's a chapter where they explain Swing's threading model to great detail.
Basically in Swing, any code that modifies the GUI should be executed in the Event Dispatcher Thread. The SwingUtilities class that you are using there provides you with an easy way to post events to the event queue that is then dispatched by the EDT. That's what the invokeLater method does, it takes a new Runnable() as argument which is ultimately executed on the EDT.
From the book:
The invokeLater() implementation takes
care of creating and queuing a special
event that contains the Runnable. This
event is processed on the EDT in the
order it was received, just like any
other event. When its time comes, it
is dispatched by running the
Runnable’s run() method.
This is a pretty common element of all GUI programming. You have one thread that handles drawing the GUI, getting input, and running callbacks. If another thread tries to change the GUI related objects, it will conflict with the GUI thread. Say, for example, it was half way through drawing something and you change the color from a different thread.
All invokeLater does is queue up something for the GUI thread to run. By "later" it's really runs almost instantly but the current thread doesn't have to wait for it. The GUI thread may be doing a draw or waiting for a callback to return which would delay executing the code you gave it.
Needs to be a member so we can change it and still use it from an inner class
protected long secret=0;
... this needs to be in your code somewhere it'll get run...
JFrame f = new JFrame("foo");
new Thread(){
public void run() {
for(;;){
try {
sleep(1000);
} catch Interrupted (Exception ix){
return;
}
// TODO update your secret key here
// please don't use random()
SwingUtilities.invokeLater(new Runnable() {
public void run() {
f.setTitle("secret "+x);
}
});
}
}
}).start();
....
Only ever update Swing from the EDT so that it paints properly.
When you are in the EDT ( running code in an event handler) you can call paintImmediately() if you really must.
If you're all looking to do is update the UI on a known schedule, try something like the following. This assumes that a JFrame is the component you wish to update every 1 second.
private static final int WAIT_LENGTH = 1000; // 1 second
private JFrame frame = new JFrame();
// Thread will update the UI (via updateUI() call) about every 1 second
class UIUpdater extends Thread {
#Override
void run() {
while (true) {
try {
// Update variables here
}
catch (Exception e) {
System.out.println("Error: " + e);
}
finally {
frame.repaint();
Thread.sleep(WAIT_LENGTH);
}
}
}
}
To start this thread:
UIUpdater t = new UIUpdater();
t.start();