今天我和很多同学一直在讨论这个话题,他们每个人都在不同的想法上“滥用”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可能不是支持我们正在寻找的所有操作的编程语言......
答案 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,这样可以让你更深入地了解绘画是如何运作的。
此外,不要以为你是在掌控,你不是。如果你试图“控制”控制,那么就要准备好让你的脸快速爆炸。理解这个过程并使用它。
看看这些(简单的)例子......