An applet I am creating uses Timers for its animation.

Even though the Timer is set to repeat at a constant 30ms, the applet's framerate on my computer versus on my brother's laptop is significantly better.

Is there a chance that on slower computers, the Timer "ticks" slower, so to speak?

Or is it because the Timer pauses when the actionPerformed() method is called (like a method within a method which causes a longer delay)?

How can I either fix or get around the problem?

Thanks

Is that a java.util.Timer or a javax.swing.Timer? Some timers run from the previous execution, others run from the previous scheduled time even if the execution was delayed. You want the second type.
The way to get a fixed-rate animation when the CPU loading is high (eg slow computer) is to use java.util.Timer's scheduleAtFixedRate to execute the actual simulation model at a fixed rate, calling repaint() after each update. Swing can then schedule screen updates as fast as possible. If the CPU loading gets too high the model will continue to update correctly, but screen refreshes will be merged/skipped, so you get a choppy but full-speed animation. Of course, if the CPU can't even keep up with the model updating than all you can do is to increase the update periods or get a better CPU.

Thanks for the fast reply, James.

I'm sad to say that java.util.Timer.scheduleAtFixedRate() did not work :'( My brother's laptop still updates slower than my desktop

There is one thing that I neglected to say. The Timer is not just for painting the screen, there are also calculations being done each time the Timer goes off.

When you said that refreshes would be "merged/skipped", does that mean that some calculations are skipped? This seems unusual because my applet is not very resource-consuming. Even a slow computer should be able to complete the calculations in time, right?

Are there any other possible causes?

Edited 3 Years Ago by kedxu

Rule 1: never do anything other than painting in your paint/paintComponent method. You have no direct control over how often that will be called, so you lose control of the animation speed. Here's a runnable demo program thatshows how to separate animation model logic from screen painting...

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.TimerTask;
import javax.swing.*;

public class Animation1 extends JPanel {
   // Basic architecture demo for multi-sprite animation

   public static void main(String[] args) {
      // create and display the animation in a JFrame
      final JFrame frame = new JFrame("Animation 1 (close window to exit)");
      Animation1 animationPanel = new Animation1(600, 400);
      frame.add(animationPanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setVisible(true);
   }

   private ArrayList<SimpleSprite> sprites = new ArrayList<SimpleSprite>();

   final static int TIMER_MSEC = 30; // mSec per clock tick

   Animation1(int width, int height) {
      setPreferredSize(new Dimension(width, height));
      sprites.add(new SimpleSprite(Color.blue, 0, 35, 2, 1));
      sprites.add(new SimpleSprite(Color.red, 0, 250, 2, -1));
      startTimer();
   }

   void startTimer() {
      // use java.util Timer rather than javax.swing Timer
      // to avoid running intensive simulation code on the swing thread
      java.util.Timer timer = new java.util.Timer();
      TimerTask timerTask = new TimerTask() {
         @Override
         public void run() {
            updateSimulation();
         }
      };
      timer.scheduleAtFixedRate(timerTask, 0, TIMER_MSEC);
   }

   public void updateSimulation() {
      // called by Timer every TIMER_MSEC milliseconds
      for (SimpleSprite s : sprites) {
         s.update(); // update position of the sprite
      }
      repaint(); // request Swing to schedule re-paint of screen
   }

   @Override
   public void paintComponent(Graphics g) {
      // screen refresh - called by Swing as needed
      Graphics2D g2d = (Graphics2D) g;
      paintBackground(g2d);
      for (SimpleSprite s : sprites) {
         s.draw(g2d);// draw the sprite at latest positions
      }
   }

   void paintBackground(Graphics2D g2d) {
      // could be an image file etc, this is just plain grey
      g2d.setColor(Color.LIGHT_GRAY);
      g2d.fillRect(0, 0, getWidth(), getHeight());
   }



}

class SimpleSprite {
   // basic x,y movement at constant velocity

   float x, y, dx, dy; // position and velocity (pixels/TIMER_MSEC)
   Color color;

   public SimpleSprite(Color color, float x, float y, float dx, float dy) {
      // initial position and velocity
      this.color = color;
      this.x = x;
      this.y = y;
      this.dx = dx;
      this.dy = dy;
   }

   public void update() { // update position and velocity every n milliSec
      x += dx; // velocity in x direction
      y += dy; // velocity in y direction
   }

   public void draw(Graphics2D g2d) {
      g2d.setColor(color);
      g2d.fillOval((int) x, (int) y, 100, 100); // draw this at latest position.
   }

}

ps: you're not doing any IO (file or network) in your paint are you?

Thank you so much, you've really helped a lot!

I think the initial problem was that the laptop was indeed terribly slow. I'm going to try running it through a bat and allocate more memory, if that helps? Not familiar with that stuff...

As for the things inside the paint method: (1) Luckily the I/O is outside the method but (2) unfortunately, the class that does the drawing inside paint() also does the calculations. It's rather tedious to separate it. Are the consequences of leaving it there that bad?

Lastly, will marking this question as solved lock it? You've already answered my initial question, but I'd still like to hear back about the second issue.

Amrking "solved" does not close or lock the thread, so ppeople can continue to contribute to it.
Before doing anything with the code I'd take a closer look at the laptop's speed. If it really is too slow a machine then there's not a lot you can do other than to lower the frame rate. If you post your paint code we can look for any obvuous inefficiencies.

This article has been dead for over six months. Start a new discussion instead.