If you want to stick with the Timer
class you can do something like the following:
public class TimerExample {
private final Timer timer = new Timer();
private TimerTask timerTask;
public void setUpButton(Button btn, Circle cir) {
btn.addEventHandler(MouseEvent.MOUSE_PRESSED, me -> {
timerTask = new TimerTask() {
@Override
public void run() {
Platform.runLater(()
-> circle.setTranslateX(circle.getTranslateX() + 1);
}
};
timer.schedule(timerTask, 0L, 10L);
});
btn.addEventHandler(MouseEvent.MOUSE_RELEASED, me -> {
timerTask.cancel();
timerTask = null;
timer.purge(); // So TimerTasks don't build up inside the Timer
// I'm not 100% sure this must/should be called
// every time
});
}
}
When using a Timer
you must schedule TimerTasks
with it. As you can see I used timer.schedule(timerTask, 0L, 10L)
which means that the timerTask
will run after an initial delay of 0 milliseconds
and then every 10 milliseconds
. This scheduling happens when the button is pressed. When the mouse is released the TimerTask
gets cancelled (won't run again) then I set the variable to null and purge the Timer
to remove any references to the TimerTask
.
In the run
method you must manipulate the circle in Platform.runLater(Runnable)
since the TimerTask
will not be called on the FxApplication Thread.
Personally, if sticking with something like a timer, I would prefer to use an javafx.animation.AnimationTimer
. This is due to the fact the AnimationTimer
's handle(long)
method is called on the FxApplication Thread once every frame.
Something like this:
public class AnimationTimerExample {
public void setUpButton(Button btn, Circle circle) {
AnimationTimer timer = new AnimationTimer() {
private final long delay = 10_000_000L; // This must be in
// nanoseconds
// since "now" is in
// nanoseconds
private long lastExecution;
@Override
public void handle(long now) {
if (now - (lastExecution + delay) <= 0L {
// Move circle
lastExecution = now;
}
}
};
btn.addEventHandler(MouseEvent.MOUSE_PRESSED, me -> timer.start());
btn.addEventHandler(MouseEvent.MOUSE_RELEASED, me -> timer.stop());
}
}
Here you have to manually calculate when to run based on delay, but this avoids any threading issues.