简体   繁体   中英

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). My problem is that when I call super.paint(g) it causes my screen to flicker. 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(). In the paint method I call super and use the paint() method's graphic to draw the image. This causes my screen to flicker even when rendering 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. Any ideas advice would be helpful!

EDIT - Solved

When setting my image in the Render.render() method repaint() was likely automatically called. I then called repaint() immediately after cause a double refresh. Removing my own repaint() call solved the issue.

Curiously before when I called repaint(), removing super.paint() also solved the issue. 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). It is not recommended to call swing components from outside the AWT thread. If it is AWT thread it will block the painting during the sleep.

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.

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. 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. 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.

If I add the repaint() call back in the flashing returns.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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