在Java中围绕repaint()工作
我计划写一个简单的太空射手。我已经读到repaint()方法只是一个请求,并不是每次调用它时都执行。我相信我已经注意到了这一点,因为我的宇宙飞船在移动时往往会稍微滞后。目前,我只是用JPanel的paintComponent()方法绘制我的飞船,并定期调用repaint()(我的面板也可以运行)。鉴于repaint()可能会把我搞砸,我正试图找到一种方法在它周围工作,但我已经没有主意了。到目前为止,我掌握的代码是:在Java中围绕repaint()工作,java,swing,bufferedimage,paintcomponent,Java,Swing,Bufferedimage,Paintcomponent,我计划写一个简单的太空射手。我已经读到repaint()方法只是一个请求,并不是每次调用它时都执行。我相信我已经注意到了这一点,因为我的宇宙飞船在移动时往往会稍微滞后。目前,我只是用JPanel的paintComponent()方法绘制我的飞船,并定期调用repaint()(我的面板也可以运行)。鉴于repaint()可能会把我搞砸,我正试图找到一种方法在它周围工作,但我已经没有主意了。到目前为止,我掌握的代码是: private void renderGraphics() { if (
private void renderGraphics() {
if (MyImage == null) {
MyImage = new BufferedImage(getPreferredSize().width,
getPreferredSize().height, BufferedImage.TYPE_INT_RGB);
}
MyGraphics = MyImage.getGraphics();
MyGraphics.setColor(Color.BLACK);
MyGraphics.fillRect(0, 0, getPreferredSize().width, getPreferredSize().height);
MyGraphics.drawImage(ship.getImage(), ship.getCurrentX(), ship.getCurrentY(), null);
}
这个想法是创建我自己的图形,然后让JPanel绘制它,并在我的run()方法中不断调用它而不是repaint(),但是我不知道如何做。我会通知你关于这件事的任何意见。任何绘图都将在Swing线程中执行,因此无论你尝试做什么,都不会有帮助
确保您没有在swing线程中执行任何冗长的计算,这可能会在需要执行重新绘制时立即停止执行它任何图形仍将在swing线程中执行,因此无论您尝试如何处理,它都不会有帮助
确保您没有在swing线程中执行任何冗长的计算,这可能会在需要执行重新绘制时立即停止执行重新绘制将所有逻辑分成两部分。静态和动态。(例如海洋和移动的船舶。船舶在静态海洋图像上改变形状/位置) 在图像中绘制静态内容一次,然后在paintComponent()中使用该图像。在静态图像之后调用动态零件绘制
使用setClip()限制重新绘制区域。将所有逻辑分为两部分。静态和动态。(例如海洋和移动的船舶。船舶在静态海洋图像上改变形状/位置) 在图像中绘制静态内容一次,然后在paintComponent()中使用该图像。在静态图像之后调用动态零件绘制
使用setClip()限制重新绘制区域。有多种方法可以实现此目的 最好的方法可能是使用
BufferStrategy
并利用它,其中我包含了一个应该适合您的代码片段
您可以更进一步,完全放弃Swing,只需使用Frame/buffer策略。在我的问题中有一个完全有效的示例(代码片段就是从中提取和改编的):
无论如何,这里有一个实现BufferStrategy
,您应该可以直接访问:
// you should be extending JFrame
public void addNotify() {
super.addNotify();
createBufferStrategy(2);
}
private synchronized void render() {
BufferStrategy strategy = getBufferStrategy();
if (strategy==null) return;
sizeChanged = false;
// Render single frame
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
MyGraphics draw = strategy.getDrawGraphics();
draw.setColor(Color.BLACK);
draw.fillRect(0, 0, getPreferredSize().width, getPreferredSize().height);
draw.drawImage(ship.getImage(), ship.getCurrentX(), ship.getCurrentY(), null);
draw.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (strategy.contentsRestored());
// Display the buffer
strategy.show();
// Repeat the rendering if the drawing buffer was lost
} while (strategy.contentsLost());
}
有多种方法可以做到这一点 最好的方法可能是使用
BufferStrategy
并利用它,其中我包含了一个应该适合您的代码片段
您可以更进一步,完全放弃Swing,只需使用Frame/buffer策略。在我的问题中有一个完全有效的示例(代码片段就是从中提取和改编的):
无论如何,这里有一个实现BufferStrategy
,您应该可以直接访问:
// you should be extending JFrame
public void addNotify() {
super.addNotify();
createBufferStrategy(2);
}
private synchronized void render() {
BufferStrategy strategy = getBufferStrategy();
if (strategy==null) return;
sizeChanged = false;
// Render single frame
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
MyGraphics draw = strategy.getDrawGraphics();
draw.setColor(Color.BLACK);
draw.fillRect(0, 0, getPreferredSize().width, getPreferredSize().height);
draw.drawImage(ship.getImage(), ship.getCurrentX(), ship.getCurrentY(), null);
draw.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (strategy.contentsRestored());
// Display the buffer
strategy.show();
// Repeat the rendering if the drawing buffer was lost
} while (strategy.contentsLost());
}
仅针对您在此处发布的代码: 1/如果您想显示,那么最好、最简单的方法是 2/正如你提到的
Runnable{…}.start()代码>Swing是简单的线程,所有到GUI的输出都必须在EDT上完成;您必须查看,结果是来自后台任务的所有输出必须包装到invokeLater()
,如果performancie有问题,则包装到invokeAndWait()
3/如果要切换(在JComponents
)/add/delete/changeLayout
则必须调用revalidate()+repaint()
作为具体代码块中的最后一行
编辑:
肮脏的黑客行为将是仅针对您在此处发布的代码:
1/如果您想显示,那么最好、最简单的方法是
2/正如你提到的Runnable{…}.start()代码>Swing是简单的线程,所有到GUI的输出都必须在EDT上完成;您必须查看,结果是来自后台任务的所有输出必须包装到invokeLater()
,如果performancie有问题,则包装到invokeAndWait()
3/如果要切换(在JComponents
)/add/delete/changeLayout
则必须调用revalidate()+repaint()
作为具体代码块中的最后一行
编辑:
dirty hack将在没有任何参数的情况下调用repait,这意味着整个面板都被重新绘制
如果需要重新绘制部分屏幕(宇宙飞船已移动到其他位置),则应使舒尔仅重新绘制屏幕的这些部分。不应触摸保持不变的区域
“重新绘制”获取应重新绘制的矩形的坐标。移动船舶时,您应该知道船舶的旧坐标以及船舶应移动到的坐标
repaint( oldShipCoordinateX, oldShipCoordinateY, shipWidth, shipLength );
repaint( newShipCoordinateX, newShipCoordinateY, shipWidth, shipLength );
这通常比不带参数调用repaint()快得多。但是,您需要额外的努力来记住船舶的最后位置,并且必须能够计算船舶的新位置
另请参见:-尤其是步骤3在没有任何参数的情况下调用repait意味着整个面板都被重新绘制
如果需要重新绘制部分屏幕(宇宙飞船已移动到其他位置),则应使舒尔仅重新绘制屏幕的这些部分。不应触摸保持不变的区域
“重新绘制”获取应重新绘制的矩形的坐标。移动船舶时,您应该知道船舶的旧坐标以及船舶应移动到的坐标
repaint( oldShipCoordinateX, oldShipCoordinateY, shipWidth, shipLength );
repaint( newShipCoordinateX, newShipCoordinateY, shipWidth, shipLength );
这通常比不带参数调用repaint()快得多。但是,您需要额外的努力来记住船舶的最后位置,并且必须能够计算船舶的新位置
另请参见:-尤其是步骤3