|
|
< Day Day Up > |
|
5.14 Updating the DisplaySometimes an application program needs to flush outstanding paint events.[10] For example, when a Shell is disposed of, it is hidden, exposing other Shells underneath. Paint events are queued by the operating system, and the exposed areas are drawn when the application program calls readAndDispatch(). If readAndDispatch() is called right away, the events are dispatched, and the newly exposed areas are drawn immediately. However, if the program is busy running a long operation in the user interface thread, the redraw will be delayed until the operation is finished and the thread gets back to the event loop. Until that time, the exposed areas remain unpainted.
Typically, an application gets back to the event loop quickly so that the user will not notice the small delay. In addition, if more drawing events are created before previous ones are handled, the operating system will merge drawing events for overlapping areas into a single drawing event as an optimization. This reduces the amount of drawing that is done, gets rid of flicker, and allows the application to draw faster. To handle the case where the program runs a long operation in the user interface thread or otherwise needs to force the screen to be redrawn, use the update() Display method.
The following program creates two shells, then disposes of the second, using update() to force the first shell to draw before running the event loop.
public static void main(String[] args) {
Display display = new Display();
Shell shell1 = new Shell(display);
shell1.setText("shell1");
shell1.setBounds(50, 50, 200, 100);
shell1.open();
Shell shell2 = new Shell(display);
shell2.setText("shell2");
shell2.setBounds(60, 60, 200, 100);
shell2.open();
shell2.dispose();
System.out.println("Waiting ... shell1 is not drawn.");
try {Thread.sleep(5000);} catch (Throwable th) {};
display.update();
System.out.println("Waiting ... shell1 is drawn.");
try {Thread.sleep(5000);} catch (Throwable th) {};
System.out.println("Running the event loop.");
while (!shell1.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
Instead of using update(), the example code could have flushed all outstanding events by using readAndDispatch() to run an event loop (see the section Reading and Dispatching). This would cause the first shell to draw but would also dispatch any other events that might be pending. In this simple example, the next thing the code does after the update() is to run the event loop, dispatching the events. However, flushing events instead of using update() in order to deliver outstanding redraws is generally disastrous. Consider the following code fragment. shell2.dispose(); while (display.readAndDispatch()); Rectangle rect = shell1.getBounds(); Imagine that shell2 has an SWT.Dispose listener that runs a long operation in the user interface thread. The user gets impatient and starts typing, clicking, and closing windows. None of these events is delivered until dispose() completes and readAndDispatch() runs, at which point they all come flooding in. Not only does shell1 redraw but the user may have closed it, causing getBounds() in the next line of code to issue SWTException("widget is disposed"). The worst part about all of this is that this behavior is nondeterministic. Sometimes the bug will happen, sometimes it will not, making it hard to recreate and debug.
|
|
|
< Day Day Up > |
|