In my Java application, when the main module is invoked, i start my SWT GUI in a separate thread. I need to perform some long opertations in the main thread and update the GUI thread. When I try to update the GUI thread from the main thread i.e. change a label text or something, i get a java.lang.NullPointerException
. From what I've read online is because SWT doesn't allow non-UI threads to update UI objects. How can I update the GUI thread from the main thread.
I've found some examples online but they all deal with the scenario in which the GUI runs in the main thread and long operation is in separate thread. My scenario is the total opposite.
Could someone tell me how I can update widgets in the GUI thread?
To say things short, SWT is a single-threaded UI toolkit. As a consequence, widgets must be updated in SWT event thread, like in Swing. Thus, you'll have to call the refresh using anonymous Runnable
classes :
Display.getDefault().asyncExec(new Runnable() {
public void run() {
someSwtLabel.setText("Complete!");
}
});
For a longer explanation, this JavaLobby article is a good introduction to this threading usage model.
I think you are getting java.lang.NullPointerException
because you are trying to access the GUI component before it is created. Ideally you should wait for the gui component to get created... for example...
I create a single GUI in a separate thread... like this
package test;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
public class GUIThread implements Runnable
{
private Display display;
private Label label;
public Display getDisplay(){
return display;
}
public void run()
{
display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout());
shell.setLayoutData(new GridData(SWT.FILL,SWT.FILL,true,false));
label = new Label(shell,SWT.NONE);
label.setText(" -- ");
shell.open();
shell.pack();
while (!shell.isDisposed()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose();
}
public synchronized void update(final int value)
{
if (display == null || display.isDisposed())
return;
display.asyncExec(new Runnable() {
public void run() {
label.setText(""+value);
}
});
}
}
And in my main method i do something like this....
package test;
import org.eclipse.swt.widgets.Display;
public class Main
{
public static void main(String[] args) throws Exception
{
final GUIThread gui = new GUIThread();
Thread t = new Thread(gui);
t.start();
Thread.sleep(3000); // POINT OF FOCUS
Display d = gui.getDisplay();
for(int i = 0; i<100; i++)
{
System.out.println(i + " " + d);
gui.update(i);
Thread.sleep(500);
}
}
}
Now if we comment out the POINT OF FOCUS
in the above code then I will always get NullPointerException
... But a delay of 3 seconds gives my GUI thread enough time to be in ready state and hence it doesn't through NullPointerException
.....
In scenario like this you have to efficiently use the wait
and yield
methods... otherwise it would result in "Hard to find Bugs"... i.e. wait for UI to properly instantiate and then yield...
Also the actual processing is done in main thread and GUI is running in separate thread... to communicate properly it is good to have some shared and synchronized data structure... or it could be done using socket communication... your main thread populating some port
and your GUI thread asynchronously
listening on that port....
Hope this will through some light on your problem....
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With