java paint(g),repaint(),update(g)后端和本地重绘

时间:2013-01-11 22:37:50

标签: java swing awt backend graphics2d

今天我和很多同学一直在讨论这个话题,他们每个人都在不同的想法上“滥用”Java2D API进行简单的2D游戏。

我正在使用扩展JComponent的类并覆盖paintComponent()方法来获取Graphics2D对象,并从那里定义我的渲染逻辑。修改后的JComponent是我覆盖contentPane的{​​{1}}。

我的问题出现了:在JFrame的后端调用paint(Graphics)repaint()update(Graphics)对我的屏幕做了什么不同的事情?我提到当从我的“帧定时器”调用除JFrame以外的任何东西(每秒调用50次这个方法)时,屏幕的某些部分有时闪烁,我清楚地告诉它渲染的一些东西是不可见的(或者快速闪烁)一切都感觉不对劲。这有什么区别?我试图深入研究AWT后端的源代码,直到repaint()EventQueue以某种方式进行管理,但我在那里停下来,以避免我的大脑出现非常难看的代码。

同样在讨论整个PaintEvent时,我们只是重新绘制了与模型中明确变化对应的屏幕位置的“策略”,从而节省了CPU / GPU的功耗。虽然它仍然需要逻辑来完成这些事情(以及动画),但下一个问题是我如何“访问”绘制屏幕的repaint(),以便我可以参考我的渲染已经完成的工作

是的,我们已经经常听到Java可能不是支持我们正在寻找的所有操作的编程语言......

1 个答案:

答案 0 :(得分:6)

  

我的问题出现了:调用有什么不同的东西   JFrame中的paint(Graphics),repaint()和update(Graphics)   后端做我的屏幕?我什么时候打电话给我   来自我的“帧定时器”的repaint()(调用问题50中的方法)   一秒钟)屏幕的某些部分有时闪烁,   我清楚地告诉它渲染的一些东西是不可见的(或闪烁   很快就会出现问题。这有什么区别?   我试图深入研究AWT后端的源代码到EventQueue   PaintEvent以某种方式管理,但我停在那里保存我的   来自极其难看的代码的大脑。

在Swing中安排绘画是RepaintManager的责任。它(除其他外)负责确定需要重新绘制应用程序的哪些区域,并在事件调度线程的上下文中安排这些更新。

当重绘可能完全取决于重绘经理。重新绘制的区域也部分取决于重绘管理器,重绘管理器可以选择将多个重绘请求合并到一个重绘事件中,从而节省时间和CPU。

一般情况下,除了无法实际创建图形上下文这一事实外,您永远不应该调用paint(Graphics)update(Graphics),重绘管理器会为您执行此操作。即使您想要打印屏幕,也应该使用组件的print(Graphics)方法,除了它不是双缓冲的事实,还有与尝试将缓冲区复制回本地对等方有关的问题;)

通常会出现闪烁,因为您是从非双缓冲上下文绘制的,例如覆盖paint而不是paintComponent。一般来说,在极少数情况下,您实际上需要覆盖顶级容器的paint方法,例如JFrame

  

当讨论整个重绘()的事情时,我们来到了   仅重新绘制与之对应的屏幕位置的“策略”   模型的明确变化,节省了我们的CPU / GPU功率。虽然它   仍然需要逻辑来完成这些事情(以及动画),   接下来的问题是如何“访问”绘制的FrameBuffer   屏幕,所以我可以参考我已经完成的工作   渲染。

通常,除非您真的需要这样做,否则不要担心。如果你小心你的重绘代码(你可以实际安排一个区域重新绘制,而不是重新绘制整个组件),你真的不需要关心。确保您使用JComponent的祖先并使用paintComponent方法获得自动双缓冲......

另一个问题是,你真的不知道组件什么时候可以请求自己重新绘制它,例如响应鼠标移动或组件属性的更改......

访问“帧缓冲区”可能真的不是一个好主意,更好的是生成自己的缓冲区(使用类似BufferedImage之类的东西),渲染到它然后将其呈现给屏幕(屏幕外缓冲)。这样你就可以生成自己的“FrameBuffer”

现在,如果你真的很绝望,你可以看看BufferStrategy

但我建议你在深入研究之前先看看Painting in AWT and Swing,这样可以让你更深入地了解绘画是如何运作的。

此外,不要以为你是在掌控,你不是。如果你试图“控制”控制,那么就要准备好让你的脸快速爆炸。理解这个过程并使用它。

看看这些(简单的)例子......