Reputation: 529
I have a working Java application (about 10k loc) which started as a command line program. A few months ago I "enhanced" it to be a very simple unthreaded SWT application, which added very little but was a step towards what I am trying to do now.
I am trying to make the invocation of the worker code to be run in a thread. I have read a good many recommendations on the internet, and have come up with a prototype:
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();
}
}
The Worker class represents the bulk of my application,
When I run this, the output lines start appearing every second, as expected, but when I try to interact with the window in any way (eg to move it), at first the window is unresponsive, but then the output stops displaying, the window is movable, and nothing further appears in the window until the end of processing, when everything remaining is displayed all at once, and the end result LOOKS correct.
If I leave the window untouched, it displays correctly.
What am I doing wrong?
Upvotes: 1
Views: 4738
Reputation: 3085
You are blocking UI by calling sleep() on UI Thread.
Use below method on Display
if you want to update UI periodically
org.eclipse.swt.widgets.Display.timerExec(int, Runnable)
Upvotes: 1
Reputation: 31
You need to start your worker in its own thread. As soon you get a result you can insert it into your gui by calling display.asyncExec from the worker-thread.
there is a snippet doing something similar here: Snippet7
In this Snippet they are doing it by syncExec, which blocks your worker until the display-thread executed the runnable. This can be easier to synchronize. Or see here
Upvotes: 3
Reputation: 14361
This looks to be the trouble spot. Worker
sleeps the thread.
Display.getDefault().asyncExec(new Runnable() {
public void run() {
new Worker(text).work();
}
});
It appears to me that you are creating a new Worker
which looks like it calls Thread.sleep()
which will Block
the thread. In this case, it's your GUI thread since it's being executed from inside it!
Fix this by removing that offending Thread.sleep()
. I try to steer clear of Thread.sleep()
in production code.
To keep your timing, you can try moving the asyncExec
into your Worker
(untested)
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();
}
}
}
}
Upvotes: 1