# 被动与主动渲染

> 原文： [https://docs.oracle.com/javase/tutorial/extra/fullscreen/rendering.html](https://docs.oracle.com/javase/tutorial/extra/fullscreen/rendering.html)

如前所述，大多数全屏应用程序通常在绘图过程中掌控时效果更好。在传统的窗口 GUI 应用程序中，何时绘制的问题通常由操作系统处理。在窗口环境中操作时，这非常有意义。窗口化应用程序不知道用户何时将移动，调整大小，公开或覆盖另一个窗口的应用程序，直到它实际发生。在 Java GUI 应用程序中，操作系统向 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 程序员来说都很烦人。

在全屏独占模式下，您不必再担心窗口被调整大小，移动，暴露或遮挡（除非您忽略了我关闭调整大小的建议）。相反，应用程序窗口直接绘制到屏幕上（_ 活动渲染 _）。这简化了绘画，因为您不需要担心绘画事件。实际上，当处于全屏独占模式时，操作系统提供的绘制事件甚至可能在不适当或不可预测的时间传递。

在全屏独占模式下，绘图代码通常更适合在 _ 渲染循环 _ 中完成，而不是依赖于 `paint` 方法。

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

```

这样的渲染循环可以从任何线程完成，可以是自己的辅助线程，也可以是主应用程序线程的一部分。

## 编程技巧

有关使用活动渲染的一些提示：

*   不要将绘图代码放在 `paint` 例程中。你可能永远不知道什么时候可以调用这个例程！相反，使用另一个方法名称，例如 `render（Graphics g）`，可以在窗口模式下操作时从 `paint` 方法调用，或者使用自己的图形从渲染循环。
*   在应用程序窗口和组件上使用 `setIgnoreRepaint` 方法关闭完全从操作系统调度的所有绘制事件，因为这些事件可能在不适当的时间被调用，或者更糟糕的是，最终调用 `paint` ]，这可能导致 AWT 事件线程和渲染循环之间的竞争条件。
*   将绘图代码与渲染循环分开，以便您可以在全屏独占和窗口模式下完全操作。
*   优化渲染，以便您不会一直在屏幕上绘制所有内容（除非您使用页面翻转或双缓冲，两者都在下面讨论）。
*   不要依赖`更新`或`重绘`方法来传递绘画事件。
*   不要使用重量级组件，因为这些组件仍会产生涉及 AWT 和平台窗口系统的开销。
*   如果你使用轻量级组件，比如 Swing 组件，你可能需要稍微调整它们以便它们使用 `Graphics` 进行绘制，而不是直接调用 `paint` 方法。您可以直接从渲染循环中调用 `paintComponents` ， `paintComponent` ， `paintBorder` 和 `paintChildren` 等 Swing 方法。
*   如果您只想要一个简单的全屏 Swing 或 AWT 应用程序，请随意使用被动渲染，但请记住，在全屏独占模式下，绘制事件可能有些不可靠或不必要。此外，如果您使用被动渲染，您将无法使用更高级的技术，如页面翻转。最后，如果您决定同时使用主动和被动渲染，请务必小心避免死锁 - 不建议使用此方法。