如何解决这些现象呢? 目前流行的方法是采取双缓冲区或者多缓冲区的方法。导致闪烁的原因是画布首先绘制其背景色,然后才绘制其他内容。双缓冲区的其中一种实现机制就是首先把背景色和其他内容保存在一幅图形当中,当收到重新绘图的时候,将整个图形设置到需要重画的区域,这样来达到消除闪烁的目的。清单 10 列举了这样的一种方法。
清单 10. 实现 DOUBLE BUFFEREDpublic class DoubleBufferSample { private static String text = "This is a sample about how to use double buffer to reduce flashing. "; private static int index = 0; private Canvas canvas; public static void main(String[] args) { final DoubleBufferSample inst = new DoubleBufferSample(); final Display display = new Display(); Shell shell = new Shell(display); inst.createContents(shell); shell.open(); Runnable runnable = new Runnable() { public void run() { display.timerExec(20, this); inst.canvas.redraw(); } }; display.timerExec(20, runnable); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.timerExec(-1, runnable); display.dispose(); } private void createContents(final Shell shell) { shell.setLayout(new FillLayout()); canvas = new Canvas(shell, SWT.COLOR_RED /*| SWT.DOUBLE_BUFFERED*/); canvas.addPaintListener(new PaintListener() { public void paintControl(PaintEvent event) { Image image = new Image(shell.getDisplay(), canvas.getBounds()); GC gc = new GC(image); gc.setBackground(event.gc.getBackground()); gc.fillRectangle(image.getBounds()); gc.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_WHITE)); if(index < text.length() - 1) index ++; else index = 0; gc.drawText(text.substring(0, index), 0, 0); event.gc.drawImage(image, 50, 50); image.dispose(); gc.dispose(); } }); } }
还有一种更简单的方法, Eclipse 3.1 Release 之后,SWT 提供了样式 SWT.DOUBLE_BUFFERED,开发者是需要设置此样式就可以轻松的使用双缓冲区。在 Linux GTK 平台上,org.eclipse.swt.widgets.Canvas 默认已经支持 SWT.DOUBLE_BUFFERED 。代码见清单 11 。我们鼓励大家使用 SWT.DOUBLE_BUFFERED 而不是按照清单 10 所示那样自己手动去实现双 / 多缓冲区,在某些特定的情况下,我们需要综合很多方法才能真正意义上来消除闪屏。
清单 11. 设置 SWT.DOUBLE_BUFFERED 样式canvas = new Canvas(shell, SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
绘图策略通常当一个窗口变大或者变小、隐藏或者显示,系统会发事件通知需要对当前窗口进行重画。 但是过于频繁的对窗口进行重绘,势必会影响应用程序的性能。鉴于此, SWT 是用了延迟更新策略。
尽管如此,我们不能保证延迟更新策略总是被采用。为了更大的控制和降低重绘的次数, SWT 允许开发者可以通过类 org.eclipse.swt.widgets.Control.中的方法 setRedraw 来决定接下来的重新绘图操作是否被忽略。 当参数为 false 时,接下来的重新绘图操作将被忽略,直到参数重新被设置成 true 时,系统不会相应任何重画事件。
结论通过以上文字的介绍,并结合文章 SWT 全接触和 SWT 图像处理入门,相信你能够对 SWT 图像处理和绘图技术有了一定的了解。我们可以看出,SWT 不仅仅对基本绘图功能封装的比较好,开发人员可以方便地绘制各种图形和各式各样的直线等,SWT 还允许开发人员在高级模式下使用 GDI+ 的高级特性:变换、路径、透明度、反锯齿等。对于 Java 开发人员来说,采用 SWT 进行绘图不失为一个明智的选择。