Search code examples
javaswingjframepaint

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?


Solution

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