据我所知,通过在线阅读以及其他在线资源(例如this),您无法从其他线程访问SWT对象。
的确,当我尝试这样做时:
课程菜单:
public class Menu {
public static void main(String args[]) {
System.out.println("Main thread: "+Thread.currentThread().getId()); // prints 1
final Display display=new Display();
final Shell shell=new Shell(display);
Label l=new Label(shell, SWT.SHADOW_IN);
l.setText("Some label");
l.pack();
SecondThread second_thread=new SecondThread(l);
Thread t=new Thread(second_thread);
t.start();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
Class SecondThread:
public class SecondThread implements Runnable {
private Label label;
public SecondThread(Label l) {
label=l;
}
@Override
public void run() {
System.out.println("Second thread: "+Thread.currentThread().getId()); // prints 8
for (int i=0; i<10000; ++i) {
try {
Thread.sleep(3000); // waiting three seconds...
} catch (InterruptedException e) {
e.printStackTrace();
}
label.setText("i is: "+i); // SWTException is thrown here
}
}
}
抛出SWTException:
Exception in thread "Thread-0" org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.widgets.Widget.error(Unknown Source)
at org.eclipse.swt.widgets.Widget.checkWidget(Unknown Source)
at org.eclipse.swt.widgets.Label.setText(Unknown Source)
at tst.SecondThread.run(SecondThread.java:25)
at java.lang.Thread.run(Thread.java:745)
此处建议的解决方案,以及其他在线资源,是使用Display的asyncExec()
方法,其中包含:
导致runnable的run()方法被调用 用户界面线程在下一个合理的机会。呼叫者,召集者 此方法继续并行运行,并且不会通知 runnable已经完成。将null指定为runnable简单 运行时唤醒用户界面线程。
所以我试着替换:
SecondThread second_thread=new SecondThread(l);
Thread t=new Thread(second_thread);
t.start();
使用:
SecondThread second_thread=new SecondThread(l);
display.asyncExec(second_thread);
但事实证明,这并没有真正创建新的执行线程,因为输出表明:
Main thread: 1
Second thread: 1
因此,Thread.sleep(3000)
调用使GUI窗口无响应......
所以我尝试了另一种方法:
菜单:
public class Menu {
public static void main(String args[]) {
System.out.println("Main thread: "+Thread.currentThread().getId()); // prints 1
final Display display=new Display();
final Shell shell=new Shell(display);
Label l=new Label(shell, SWT.SHADOW_IN);
l.setText("Some label");
l.pack();
SecondThread second_thread=new SecondThread(l);
Thread t=new Thread(second_thread);
t.start();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
SecondThread:
public class SecondThread implements Runnable {
private Label label;
public SecondThread(Label l) {
label=l;
}
@Override
public void run() {
System.out.println("Second thread: "+Thread.currentThread().getId()); // prints 8
for (int i=0; i<10000; ++i) {
try {
Thread.sleep(3000); // waiting three seconds...
} catch (InterruptedException e) {
e.printStackTrace();
}
updateLabel("i is: "+i);
}
}
private void updateLabel(final String string) {
Display display=Display.getCurrent(); // display is not null...
display.asyncExec(new Runnable() { // throws NullPointerException...
@Override
public void run() {
System.out.println("test");
label.setText(string);
}
});
}
}
不幸的是,这会抛出NullPointerException:
Main thread: 1
Second thread: 8
Exception in thread "Thread-0" java.lang.NullPointerException
at tst.SecondThread.updateLabel(SecondThread.java:33)
at tst.SecondThread.run(SecondThread.java:25)
at java.lang.Thread.run(Thread.java:745)
我不知道为什么......
有谁知道可能导致这种情况的原因?
答案 0 :(得分:3)
您的SecondThread
不是用户界面线程,因此Display.getCurrent()
将返回null
,因为只有用户界面线程具有当前显示。
使用Display.getDefault()
从任何线程获取显示。