0

I have a program that is just a window that draws something (no calculations, no interaction with the user etc). This program's main JPanel has a fairly complex paintComponent function - it takes about 5 to 10 ms to perform.

I set up a Timer that calls a TimerTask every 25 ms. That TimerTask just calls repaint() on the panel. That way the program should have 40 FPS.

But the panel's paintComponent method takes about 5 to 10 ms to perform. For some reason, the Timer waits for the TimerTask's run() method to complete (meaning that it waits for the panel to repaint). This way it's not repainted every 25 ms, but 30-35 ms, leading to unstable and bad FPS.

Obviously I want the calculations to be performed in the background - now the program just performs the drawing and then waits idly for 25 ms, instead of performing drawing and waiting just the remaining time.

I've tried using a swing.Timer instead of a util.Timer, that didn't work (it was the same).

I tried having two separate timers, one for drawing the graphics on a BufferedImage and a different one for putting the BufferedImage on the JPanel. That was a bit better performance-wise but flickered.

So how do I draw graphics truly in the background?

vvolhejn
  • 118
  • 1
  • 5
  • 1
    `javaxswing.Timer` is the right choice, for [example](http://stackoverflow.com/a/3256941/230513); please edit your question to include an [sscce](http://sscce.org/) that exhibits the problem you describe. – trashgod Nov 05 '13 at 21:30
  • *"but flickered"* Sounds like you are painting directly to a top level container. – MadProgrammer Nov 05 '13 at 23:08

1 Answers1

0

The best way you are going to do this is already in the answer.

Draw in the background.

You need to render the graphics onto a separate image, then just render that image onto the JPanel whenever the JPanel requests it.

One problem with your solution though, is the static sleep. You would want to instead create a new thread. This thread will be responsible for rendering onto the image. Then, depending on how much time has passed, sleep for the remainder you need too.

private final BufferedImage render = new BufferedImage(screen_width, screen_height, BufferedImage.TYPE_RGB);

public void run(){
    final long start = System.nanoTime();
    renderGraphicsOnto(render.getGraphics());
    final renderTime = System.nanoTime() - start;
    try {
        Thread.sleep(25 - renderTime / 1000000); // convert to milliseconds
    } catch(final Exception ignored){
    }
}

That's just a small example on how you may want to approach this. No form of static sleeping provided by javax.swing.Timer or java.util.TimerTask will achieve this.

Obicere
  • 2,999
  • 3
  • 20
  • 31