Java 从另一个线程更新 SWT 对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4368533/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Updating SWT objects from another thread
提问by Mridang Agarwalla
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.
在我的 Java 应用程序中,当主模块被调用时,我在一个单独的线程中启动我的 SWT GUI。我需要在主线程中执行一些长时间的操作并更新 GUI 线程。当我尝试从主线程更新 GUI 线程时,即更改标签文本或其他内容时,我得到一个java.lang.NullPointerException
. 从我在线阅读的内容来看,SWT 不允许非 UI 线程更新 UI 对象。如何从主线程更新 GUI 线程。
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.
我在网上找到了一些例子,但它们都处理GUI在主线程中运行并且长时间操作在单独线程中的场景。我的情况完全相反。
Could someone tell me how I can update widgets in the GUI thread?
有人能告诉我如何在 GUI 线程中更新小部件吗?
采纳答案by Favonius
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...
我认为您是java.lang.NullPointerException
因为您试图在创建 GUI 组件之前访问它。理想情况下,您应该等待 gui 组件创建...例如...
I create a single GUI in a separate thread... like this
我在一个单独的线程中创建了一个 GUI ......就像这样
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
.....
现在,如果我们POINT OF FOCUS
在上面的代码中注释掉,那么我将始终得到NullPointerException
...但是 3 秒的延迟使我的 GUI 线程有足够的时间进入就绪状态,因此它不会通过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...
在这种情况下,您必须有效地使用wait
和yield
方法……否则会导致“很难找到错误”……即等待 UI 正确实例化,然后产生……
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....
此外,实际的处理是在主线程中完成的,GUI 在单独的线程中运行......为了正确通信,最好有一些共享和同步的数据结构......或者它可以使用套接字通信完成......你的主线程填充一些port
和您的 GUI 线程asynchronously
侦听该端口....
Hope this will through some light on your problem....
希望这能解决您的问题....
回答by Riduidel
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 :
简而言之,SWT 是一个单线程 UI 工具包。因此,必须在 SWT 事件线程中更新小部件,就像在 Swing 中一样。因此,您必须使用匿名Runnable
类调用刷新:
Display.getDefault().asyncExec(new Runnable() {
public void run() {
someSwtLabel.setText("Complete!");
}
});
For a longer explanation, this JavaLobbyarticle is a good introduction to this threading usage model.
对于更长的解释,这篇JavaLobby文章很好地介绍了这种线程使用模型。