JFrame super.paint(g) 导致闪烁
JFrame super.paint(g) Causing Flickering
我正在使用自己的双缓冲处理渲染循环,我没有 JPanel,而是 JFrame(据我所知,JPanel 会自动双缓冲)。我的问题是,当我调用 super.paint(g) 时,它会导致我的屏幕闪烁。当我评论它时它就消失了。
ATM 我创建一个 BufferedImage 并获取它的 Graphics2D,然后在每个渲染循环中我用纯色刷新图像并调用 repaint()。在 paint 方法中,我调用 super 并使用 paint() 方法的图形来绘制图像。这会导致我的屏幕即使在渲染 1 fps 时也会闪烁。
public void run()
{
long startTime;
long runTime;
double residualTime = 0;
while(isRunning)
{
startTime = System.nanoTime();
**update.update();**
render.render();
runTime = System.nanoTime() - startTime;
if(runTime < 1e9/fpsTarget)
{
Double sleepTime = (1e9/fpsTarget - runTime) / 1e6;
residualTime += sleepTime % 1;
sleepTime -= sleepTime % 1;
if(residualTime > 1)
{
sleepTime++;
residualTime--;
}
try
{
sleep(sleepTime.longValue());
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
/*
System.out.println("\n Run time: " + runTime / 1e6);
System.out.println(" Sleep time: " + sleepTime);
System.out.println("Residual Time: " + residualTime);
*/
}
}
//fps(startTime);
}
}
public class Render
{
private Screen screen;
Graphics2D graphics;
BufferedImage image;
public Render()
{
screen = new Screen();
image = new BufferedImage(screen.getWidth(), screen.getHeight(), BufferedImage.TYPE_INT_RGB);
graphics = image.createGraphics();
}
public void render()
{
flush();
screen.setImage(image);
screen.repaint();
}
private void flush()
{
graphics.setPaint(Color.BLUE);
graphics.fillRect(0, 0, image.getWidth(), image.getHeight());
}
}
public class Screen extends JFrame
{
private BufferedImage image;
public Screen()
{
super(TITLE);
setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
setLocation(300, 150);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
@Override
public void paint(Graphics g)
{
super.paint(g);
g.drawImage(image, 0, 0, null);
}
public void setImage(BufferedImage image)
{
this.image = image;
}
我之前尝试过添加 JPanel 并通过 paintComponent() 进行渲染,但遇到了同样的问题。任何想法建议都会有所帮助!
编辑 - 已解决
在 Render.render() 方法中设置图像时,可能会自动调用 repaint()。然后我在导致双重刷新后立即调用 repaint() 。删除我自己的 repaint() 调用解决了这个问题。
奇怪的是,在我调用 repaint() 之前,删除 super.paint() 也解决了这个问题。有什么想法吗?
您似乎在处理循环中调用 sleep。
sleep(sleepTime.longValue());
如果它在单独的线程中被调用,则您是从另一个线程(不是 Swing 的 AWT 线程)调用重绘。不建议从 AWT 线程外部调用 swing 组件。如果是AWT线程它会在睡眠时阻塞绘画。
虽然这可能不是导致闪烁的主要问题,但您应该修改代码以使用 Swing 计时器,以便在 AWT 线程上调用重绘逻辑而不阻塞。
好吧,我不确定这是否是答案,但我试图向 Andrew 展示当我使用面板渲染而不是框架渲染时我的代码是什么样子,但没有取得任何成功。我删除了我更改的所有内容,并尝试研究 Ashwinee 的线程理论。在更改任何内容之前,我 运行 我的代码曾经 运行 完美。
将我当前的代码与我提交时的代码进行比较,我认为不同之处在于我删除了 Render.render() 方法中的 repaint() 语句。我唯一的猜测是 JFrame 识别出它之前绘制的某些东西发生了变化,所以它会自动重新绘制,所以我实际上每个循环都重新绘制了两次。
如果我在闪烁中添加 repaint() 回调 returns。
我正在使用自己的双缓冲处理渲染循环,我没有 JPanel,而是 JFrame(据我所知,JPanel 会自动双缓冲)。我的问题是,当我调用 super.paint(g) 时,它会导致我的屏幕闪烁。当我评论它时它就消失了。
ATM 我创建一个 BufferedImage 并获取它的 Graphics2D,然后在每个渲染循环中我用纯色刷新图像并调用 repaint()。在 paint 方法中,我调用 super 并使用 paint() 方法的图形来绘制图像。这会导致我的屏幕即使在渲染 1 fps 时也会闪烁。
public void run()
{
long startTime;
long runTime;
double residualTime = 0;
while(isRunning)
{
startTime = System.nanoTime();
**update.update();**
render.render();
runTime = System.nanoTime() - startTime;
if(runTime < 1e9/fpsTarget)
{
Double sleepTime = (1e9/fpsTarget - runTime) / 1e6;
residualTime += sleepTime % 1;
sleepTime -= sleepTime % 1;
if(residualTime > 1)
{
sleepTime++;
residualTime--;
}
try
{
sleep(sleepTime.longValue());
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
/*
System.out.println("\n Run time: " + runTime / 1e6);
System.out.println(" Sleep time: " + sleepTime);
System.out.println("Residual Time: " + residualTime);
*/
}
}
//fps(startTime);
}
}
public class Render
{
private Screen screen;
Graphics2D graphics;
BufferedImage image;
public Render()
{
screen = new Screen();
image = new BufferedImage(screen.getWidth(), screen.getHeight(), BufferedImage.TYPE_INT_RGB);
graphics = image.createGraphics();
}
public void render()
{
flush();
screen.setImage(image);
screen.repaint();
}
private void flush()
{
graphics.setPaint(Color.BLUE);
graphics.fillRect(0, 0, image.getWidth(), image.getHeight());
}
}
public class Screen extends JFrame
{
private BufferedImage image;
public Screen()
{
super(TITLE);
setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
setLocation(300, 150);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
@Override
public void paint(Graphics g)
{
super.paint(g);
g.drawImage(image, 0, 0, null);
}
public void setImage(BufferedImage image)
{
this.image = image;
}
我之前尝试过添加 JPanel 并通过 paintComponent() 进行渲染,但遇到了同样的问题。任何想法建议都会有所帮助!
编辑 - 已解决
在 Render.render() 方法中设置图像时,可能会自动调用 repaint()。然后我在导致双重刷新后立即调用 repaint() 。删除我自己的 repaint() 调用解决了这个问题。
奇怪的是,在我调用 repaint() 之前,删除 super.paint() 也解决了这个问题。有什么想法吗?
您似乎在处理循环中调用 sleep。
sleep(sleepTime.longValue());
如果它在单独的线程中被调用,则您是从另一个线程(不是 Swing 的 AWT 线程)调用重绘。不建议从 AWT 线程外部调用 swing 组件。如果是AWT线程它会在睡眠时阻塞绘画。
虽然这可能不是导致闪烁的主要问题,但您应该修改代码以使用 Swing 计时器,以便在 AWT 线程上调用重绘逻辑而不阻塞。
好吧,我不确定这是否是答案,但我试图向 Andrew 展示当我使用面板渲染而不是框架渲染时我的代码是什么样子,但没有取得任何成功。我删除了我更改的所有内容,并尝试研究 Ashwinee 的线程理论。在更改任何内容之前,我 运行 我的代码曾经 运行 完美。
将我当前的代码与我提交时的代码进行比较,我认为不同之处在于我删除了 Render.render() 方法中的 repaint() 语句。我唯一的猜测是 JFrame 识别出它之前绘制的某些东西发生了变化,所以它会自动重新绘制,所以我实际上每个循环都重新绘制了两次。
如果我在闪烁中添加 repaint() 回调 returns。