当覆盖paint或paintComponent时,需要恢复图形的原始状态

9

我意识到大多数Java代码重写paint或paintComponent,他们中的大多数在改变了图形对象的状态后并没有恢复旧状态。例如,setStroke、setRenderingHint...

我想知道,在方法返回之前,我们是否应该恢复图形对象的旧状态,这样做是否是一个好习惯。例如:

public void paintComponent(Graphics g) {
    super.paintComponet(g);
    Stroke oldStroke = g.getStroke();
    g.setStroke(newStroke);
    // Do drawing operation.
    g.setStroke(oldStroke);
}

这是一种好的实践方法吗?还是有些过度了?

2个回答

16

你不应该改变传入的Graphics对象,而是在其副本上执行所有的图形操作,然后将其丢弃。这样就完全不需要重置状态了。

public void paintComponent(Graphics g1) {
    super.paintComponent(g1);
    final Graphics2D g = (Graphics2D)g1.create();
    try {
         // ...Whole lotta drawing code...
    } finally {
         g.dispose();
    }
}

3
我将用同意的JComponent JavaDoc来支持这个答案:http://docs.oracle.com/javase/6/docs/api/javax/swing/JComponent.html#paintComponent%28java.awt.Graphics%29 - Yago Méndez Vidal

3

是的,这是一个非常好的实践。你不会因此影响性能(相对于实际绘制操作),并且如果您对图形上下文进行了不寻常的更改,这将使您免受烦恼。但不要过度使用它--例如您可能不需要担心颜色设置。

另一种方法是不对图形上下文做任何假设,在每次绘制之前设置所有必要的属性,以防它们被设置为奇怪的值。尽量避免为每个操作自由创建和处理Graphics对象。

如果修改了以下特定属性,则应始终还原:(因为它们可能导致意想不到的后果):

  • Transform - 因为对其进行的修改将叠加在一起,并且很难重置。请注意:Graphics2D的translate、shear、scale、rotate和transform方法都会修改Transform。修改变换时应谨慎使用。
  • Stroke -- 因为(至少在我的配置中),即使与默认值相等,将其保持默认状态运行速度也比任何设置快得多。不要问我为什么--这是Java2D图形管道通过使用图形硬件加速默认情况得出的结果。
  • Clip: 将导致奇怪的错误,只有部分屏幕会绘制。
  • Composite: 大多数操作可能不希望这是某些奇怪的值。

无需担心的属性包括:

  • RenderingHints。这些是您可以轻松设置和还原的内容,并且通常您希望在应用程序运行的整个时间内以某种方式保留它们(例如开启抗锯齿)。更改RenderingHints很少会破坏组件的渲染,尽管它可能会使其变得更加丑陋。
  • 背景颜色和绘制颜色。大多数情况下,绘制之前都会修改这些属性。
  • 字体:同样如此。

您应该发现创建一个Graphics对象非常便宜。 - Tom Hawtin - tackline
嗯...是的,已经纠正了。我仍然认为这不是一个好的做法,因为你永远不知道还有谁在使用Graphics对象,而且你会失去RenderingHints等设置。 - BobMcGee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接