timer.setDelay()
works for me. Here's a quick example that moves a red square across the screen. Pressing the fast-forward button makes it move faster by calling setDelay
on the timer (you'll notice the logic in my ActionListener
is identical to yours, albeit different variable names):
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TimerTest extends JFrame {
public static void main(String[] args) { new TimerTest().setVisible(true); }
private static final int DEFAULT_SPEED = 500;
private int speedCounter = 1;
private int currentSpeed = DEFAULT_SPEED / speedCounter;
private int squareX = 150;
public TimerTest() {
super("Test");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setMinimumSize(new Dimension(300, 200));
setLayout(new BorderLayout());
setLocationRelativeTo(null);
JPanel displayPanel = new JPanel(null) {
@Override
public void paintComponent(Graphics g) {
g.setColor(Color.RED);
g.fillRect(squareX, getHeight() / 2, 25, 25);
}
};
final Timer timer = new Timer(currentSpeed, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
squareX = (squareX + 15) % getWidth();
repaint();
}
});
timer.setRepeats(true);
JButton fastForwardButton = new JButton(new AbstractAction(">>") {
@Override
public void actionPerformed(ActionEvent e) {
speedCounter++;
currentSpeed = DEFAULT_SPEED / speedCounter;
timer.stop();
timer.setDelay(currentSpeed);
timer.start();
}
});
add(displayPanel, BorderLayout.CENTER);
add(fastForwardButton, BorderLayout.SOUTH);
timer.start();
}
}
One noticeable flaw with this approach is that starting/stopping the timer will cause an additional delay. For example, say the timer was set to fire every 2
seconds and it has been 1.5
seconds since the last frame. If you set the delay to 1
second and restart the timer, 2.5
seconds will have passed before the next frame fires. This could explain why "it didn't work" for you.
To avoid this issue, you could create a timer that fires at some fixed rate but only executes your logic if enough time has passed. Then change what "enough time" is when the user fast-forwards. For example, the timer could fire every 50ms
, but you only execute your logic if 500ms
has passed since the last execution. When the user fast-forwards, you could then execute your logic if 250ms
has passed instead (and so on).