英文:
Java Application is not responding after using Thread.Sleep();
问题
我目前运行以下代码时遇到了一些问题。如果我删除这部分,问题就消失了,所以我整个代码中的这部分肯定有问题。它能够正常运行并绘制我想要的内容,但是在几秒钟后(maxAddedRuntime由用户设置(毫秒)),应用程序会冻结一段时间(窗口显示未响应的消息),然后在窗口冻结的同时等待大约相同的时间后重新开始绘制。我做错了什么?
我正在使用SWT和一个画布来进行绘制。谢谢您的帮助。
public void drawNetwork(Canvas canvas, GC gc, Network network, Shell shlNetworkVisualizer) {
startTime = System.currentTimeMillis();
endTime = startTime + maxAddedRuntime;
this.drawNetworkAlg1(canvas, gc, network);
int canvasHeight = canvas.getBounds().height;
int canvasWidth = canvas.getBounds().width;
while (System.currentTimeMillis() < endTime) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
gc.fillRectangle(0, 0, canvasWidth, canvasHeight); //清除画布
for (Node node : network.node) {
//绘制一些内容
}
for (Edge edge : network.edges) {
//也可以绘制一些内容
}
}
}
英文:
I am currently having some trouble when running the follwing code. If I delete this part the problems disappear so this part of my whole code has to be the problem. It runs and draws what I want perfectly but after a few seconds (maxAddedRuntime is set via user (milliseconds)) the application freezes for a while (window is not responding Windows message) and starts over with drawing after waiting approximately the same time while the window is frozen. What do I do wrong?
I am using SWT and a canvas to draw. Thank you for your help
public void drawNetwork(Canvas canvas, GC gc, Network network, Shell shlNetworkVisualizer) {
startTime = System.currentTimeMillis();
endTime = startTime + maxAddedRuntime;
this.drawNetworkAlg1(canvas, gc, network);
int canvasHeight = canvas.getBounds().height;
int canvasWidth = canvas.getBounds().width;
while (System.currentTimeMillis()<endTime) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
gc.fillRectangle(0, 0, canvasWidth, canvasHeight); //ClearCanvas basically
for (Nodek: network.node) {
//drawSomeStuff
}
for (Edge k: network.edges) {
//alsoDrawSomeStuff
}
}
}
答案1
得分: 3
一个 SWT 应用程序必须尽快返回主 Display.readAndDispatch
循环。因此,您不能使用带有 Thread.sleep
调用的循环 - 这只会在循环结束之前锁定 UI。
相反,您可以使用 Display.timerExec
在延迟后运行代码。您可以使用它来运行单个步骤(例如,只运行一个 gc.fillRectange
),然后再次调用 Display.timerExec
来安排下一步。
public void timerExec(int milliseconds, Runnable runnable)
注意:从绘制事件中获取的 GC 仅在绘制期间有效。timerExec
调用通常应该只在画布上调用 redraw
,以触发生成新的绘制事件。
这是一个执行基本的 timerExec
调用并进行绘制的简单类:
class Progress
{
private final Canvas canvas;
private final long endTime;
Progress(Canvas c)
{
canvas = c;
endTime = System.currentTimeMillis() + 1_000;
canvas.addListener(SWT.Paint, this::paint);
canvas.getDisplay().timerExec(100, this::timer);
}
private void paint(Event event)
{
GC gc = event.gc;
int canvasHeight = canvas.getBounds().height;
int canvasWidth = canvas.getBounds().width;
gc.fillRectangle(0, 0, canvasWidth, canvasHeight);
// TODO 更多绘制
}
private void timer()
{
if (canvas.isDisposed()) { // 如果控件已关闭,则不要继续
return;
}
canvas.redraw();
if (System.currentTimeMillis() < endTime) {
canvas.getDisplay().timerExec(100, this::timer);
}
}
}
英文:
An SWT app must return to the main Display.readAndDispatch
loop as quickly as possible. So you cannot use a loop with a Thread.sleep
call - this will just lock up the UI until the loop ends.
Instead you can use Display.timerExec
to run code after a delay. You would use this to run a single step (just one gc.fillRectange for example) and then call Display.timerExec
again to schedule the next step.
public void timerExec(int milliseconds, Runnable runnable)
Note: The GC you receive from a paint event is only valid during the paint. The timerExec call should normally just call redraw
on the canvas to cause a new paint event to be generated.
Here is a simple class that does basic timerExec calls and paints:
class Progress
{
private final Canvas canvas;
private final long endTime;
Progress(Canvas c)
{
canvas = c;
endTime = System.currentTimeMillis() + 1_000;
canvas.addListener(SWT.Paint, this::paint);
canvas.getDisplay().timerExec(100, this::timer);
}
private void paint(Event event)
{
GC gc = event.gc;
int canvasHeight = canvas.getBounds().height;
int canvasWidth = canvas.getBounds().width;
gc.fillRectangle(0, 0, canvasWidth, canvasHeight);
// TODO more painting
}
private void timer()
{
if (canvas.isDisposed()) { // Don't continue if control closed
return;
}
canvas.redraw();
if (System.currentTimeMillis() < endTime) {
canvas.getDisplay().timerExec(100, this::timer);
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论