我有一个工作的Java应用程序(大约10k loc),它作为命令行程序启动。几个月前,我“强化”它是一个非常简单的无线SWT应用程序,它增加了很少,但是朝着我现在想做的一步迈进了一步。
我正在尝试调用在线程中运行的worker代码。我在网上看了很多推荐,并提出了一个原型:
package myapp;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class Console {
Display display;
Shell shell;
Text text;
private void process() {
display = new Display();
shell = new Shell(display);
shell.setLayout(new FillLayout());
shell.setLocation(new Point(80, 80));
text = new Text(shell, SWT.MULTI | SWT.V_SCROLL | SWT.READ_ONLY);
shell.open();
Display.getDefault().asyncExec(new Runnable() {
public void run() {
new Worker(text).work();
}
});
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
class Worker {
Text text;
public Worker(Text t) {
text = t;
};
void work() {
for (int i = 0; i < 30; i++) {
text.append("hello " + i + "\n");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
new Console().process();
}
}
Worker类代表我的大部分应用程序,
当我运行它时,输出行开始每秒出现,如预期的那样,但是当我尝试以任何方式与窗口交互时(例如移动它),首先窗口没有响应,但是输出停止显示,窗口是可移动的,窗口中没有任何进一步显示,直到处理结束,剩下的所有内容一次全部显示,最终结果显示正确。
如果我不改动窗户,它会正确显示。
我做错了什么?
答案 0 :(得分:3)
您需要在自己的线程中启动您的worker。一旦得到结果,您可以通过从工作线程调用display.asyncExec将其插入到您的gui中。
这里有一段类似的代码: Snippet7
在这个Snippet中,他们通过syncExec来执行它,它会阻止你的worker直到display-thread执行runnable。这可以更容易同步。或者参见here
答案 1 :(得分:1)
这看起来很麻烦。 Worker
睡觉了。
Display.getDefault().asyncExec(new Runnable() {
public void run() {
new Worker(text).work();
}
});
在我看来,您正在创建一个新的Worker
,它看起来像调用Thread.sleep()
Block
线程。在这种情况下,它是你的GUI线程,因为它是从它内部执行的!
通过删除有问题的Thread.sleep()
来解决此问题。我尝试在生产代码中避开Thread.sleep()
。
为了保持时间安排,您可以尝试将asyncExec
移至Worker
(未经测试)
class Worker {
Text text;
public Worker(Text t) {
text = t;
};
void work() {
for (int i = 0; i < 30; i++) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
text.append("hello " + i + "\n");
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
答案 2 :(得分:0)
您通过在UI线程上调用sleep()来阻止UI。
如果您想定期更新用户界面,请在Display
上使用以下方法
org.eclipse.swt.widgets.Display.timerExec(int, Runnable)