被动渲染与主动渲染

如前所述,大多数全屏应用程序通常在绘制过程中发挥更好的作用。在传统的窗口式 GUI 应用程序中,何时绘制问题通常由 os 处理。在窗口环境中操作时,这是很有意义的。窗口化的应用程序不知道用户何时会移动,调整大小,暴露或覆盖另一个窗口,直到它 true 发生为止。在 Java GUI 应用程序中,os 将绘画事件传递给 AWT,该事件确定需要绘画的内容,创建具有适当剪切区域的java\.awt\.Graphics对象,然后使用该Graphics对象调用paint方法:

// Traditional GUI Application paint method:
// This can be called at any time, usually 
// from the event dispatch thread
public void paint(Graphics g) {
    // Use g to draw my Component
}

有时将其称为被动渲染。可以想象,这样的系统会产生很多开销,这使许多对性能敏感的 AWT 和 Swing 程序员感到烦恼。

在全屏独占 Pattern 下,您不必担心窗口会被调整大小,移动,暴露或遮挡(除非您忽略了我关闭调整大小的建议)。而是将应用程序窗口直接绘制到屏幕上(活动渲染)。因为您不必担心绘画事件,所以这大大简化了绘画。实际上,在全屏排他 Pattern 下,由 os 传递的绘画事件甚至可能在不适当或不可预测的时间传递。

通常,在渲染循环中更适当地完成绘制代码,而不是在全屏独占 Pattern 下依赖paint方法:

public void myRenderingLoop() {
    while (!done) {
        Graphics myGraphics = getPaintGraphics();
        // Draw as appropriate using myGraphics
        myGraphics.dispose();
    }
}

这样的渲染循环可以从任何线程完成,无论是其自己的辅助线程还是作为主应用程序线程的一部分。

Programming Tips

有关使用主动渲染的一些技巧:

  • 不要将绘图代码放在paint例程中。您可能永远不知道该例程何时会被调用!而是使用另一个方法名称,例如render\(Graphics g\),当在窗口 Pattern 下操作时可以从paint方法调用,或从渲染循环中使用其自己的图形替代调用。

  • 在应用程序窗口和组件上使用setIgnoreRepaint方法可以完全关闭从 os 分派的所有绘制事件,因为这些事件可能在不适当的时间调用,或者更糟的是final调用paint,这可能导致 AWT 事件之间的竞争状态线程和渲染循环。

  • 将绘制代码与渲染循环分开,以便可以在全屏独占和窗口 Pattern 下完全操作。

  • 优化渲染,以免在任何时候都在屏幕上绘制所有内容(除非您正在使用页面翻转或 Double 缓冲,这两个都在下面讨论)。

  • 不要依赖updaterepaint方法来传递绘画事件。

  • 不要使用重量级的组件,因为这些组件仍然会导致涉及 AWT 和平台的窗口系统的开销。

  • 如果使用轻型组件(例如 Swing 组件),则可能需要摆弄它们,以便它们使用Graphics绘制,而不是直接由于调用paint方法而绘制。可以直接从渲染循环中调用 Swing 方法,例如paintComponentspaintComponentpaintBorderpaintChildren

  • 如果只需要简单的全屏 Swing 或 AWT 应用程序,请随意使用被动渲染,但是请记住,在全屏独占 Pattern 下,绘画事件可能有些不可靠或不必要。此外,如果使用被动渲染,则将无法使用更高级的技术,例如页面翻转。最后,如果决定同时使用主动渲染和被动渲染,请非常小心避免死锁-不建议使用此方法。