简体   繁体   English

JFrame super.paint(g)导致闪烁

[英]JFrame super.paint(g) Causing Flickering

I'm working on a rendering loop using my own double buffering, I don't have a JPanel but a JFrame (as I understand JPanel automatically double buffers). 我正在使用自己的双缓冲在渲染循环上工作,我没有JPanel而是JFrame(据我所知,JPanel会自动双缓冲)。 My problem is that when I call super.paint(g) it causes my screen to flicker. 我的问题是,当我调用super.paint(g)时,它会导致屏幕闪烁。 When I comment this out it goes away. 当我对此发表评论时,它就消失了。

ATM I create a BufferedImage and grab it's Graphics2D, then every render loop I flush the image with a solid color and call repaint(). 在ATM上,我创建一个BufferedImage并获取它的Graphics2D,然后每个渲染循环用纯色冲洗图像并调用repaint()。 In the paint method I call super and use the paint() method's graphic to draw the image. 在paint方法中,我调用super并使用paint()方法的图形绘制图像。 This causes my screen to flicker even when rendering 1 fps. 即使渲染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;
    }

I've tried adding a JPanel before and rendering through paintComponent() but had the same issue. 我尝试过添加一个JPanel并通过paintComponent()进行渲染,但是存在相同的问题。 Any ideas advice would be helpful! 任何想法建议都会有所帮助!

EDIT - Solved 编辑-解决

When setting my image in the Render.render() method repaint() was likely automatically called. 在Render.render()方法中设置图像时,可能自动调用了repaint()。 I then called repaint() immediately after cause a double refresh. 然后,我在引起两次刷新后立即调用repaint()。 Removing my own repaint() call solved the issue. 删除我自己的repaint()调用即可解决此问题。

Curiously before when I called repaint(), removing super.paint() also solved the issue. 奇怪的是,当我调用repaint()之前,删除super.paint()也解决了这个问题。 Any ideas why? 有什么想法吗?

It looks like you are calling sleep in your processing loop. 看来您在处理循环中正在调用睡眠。

 sleep(sleepTime.longValue());

If it is getting called in a separate thread, you are invoking repaint from another thread (not the Swing's AWT thread). 如果在单独的线程中调用它,那么您正在从另一个线程(而不是Swing的AWT线程)调用重绘。 It is not recommended to call swing components from outside the AWT thread. 不建议从AWT线程外部调用Swing组件。 If it is AWT thread it will block the painting during the sleep. 如果它是AWT线程,它将在睡眠期间阻止绘画。

Though this may not be the main problem causing flicker, you should modify you code to use Swing timer so that the repaint logic is called on the AWT thread and does not block. 尽管这可能不是导致闪烁的主要问题,但是您应该修改代码以使用Swing计时器,以便在AWT线程上调用重新绘制逻辑并且不会阻塞。

Well I'm not sure if this was the answer or not, but I was trying to show Andrew what my code looked like when I had a Panel rendering instead of the Frame but wasn't having any success. 好吧,我不确定这是否是答案,但是我试图向安德鲁展示当我使用面板渲染而不是框架但没有成功时我的代码是什么样的。 I deleted everything I changed and tried pursuing Ashwinee's thread theory. 我删除了所有更改内容,并尝试遵循Ashwinee的线程理论。 I ran my code once before changing anything and it was running perfectly. 在更改任何内容之前,我运行了我的代码一次,它运行良好。

Comparing my current code to when I submitted I think the difference is that I deleted my repaint() statement in the Render.render() method. 将我当前的代码与提交时的代码进行比较,我认为不同之处在于我在Render.render()方法中删除了repaint()语句。 My only guess is that JFrame recognized something that it had previously drawn changed so it automatically repainted, so I was effectively repainting twice every loop. 我唯一的猜测是,JFrame识别出它先前绘制的内容已更改,因此它会自动重新绘制,因此我实际上每个循环都重新绘制了两次。

If I add the repaint() call back in the flashing returns. 如果我添加repaint(),则在闪烁的返回中进行回调。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM