Javafx使用计时器时不在fx应用程序线程上
我正在使用这个
import java.util.Random; import java.util.Timer; import java.util.TimerTask; import javafx.application.Application; import javafx.application.Platform; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.stage.Stage; public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { Group root = new Group(); Scene scene = new Scene(root, 600, 400); primaryStage.setScene(scene); Circle circle = new Circle(300,200,50, Color.BLACK); primaryStage.setTitle("Circle"); primaryStage.setResizable(false); root.getChildren().add(circle); moveCircle(circle, scene); primaryStage.show(); } public int random(int min, int max) { return new Random().nextInt((max - min) + min); } public int random(int max) { return random(0, max); } public void moveCircle(Circle circle, Scene scene) { Platform.runLater(() -> { Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { circle.setCenterX(random((int) scene.getX())); circle.setCenterY(random((int) scene.getY())); } }, 1000, 1000); }); }
但是这个:
public void moveCircle(Circle circle, Scene scene) { Platform.runLater(() -> { Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { circle.setCenterX(random((int) scene.getX())); circle.setCenterY(random((int) scene.getY())); } }, 1000, 1000); }); }
给我这个错误:
Exception in thread "Timer-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = Timer-0 at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204) at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364) at javafx.scene.Scene.addToDirtyList(Scene.java:485) at javafx.scene.Node.addToSceneDirtyList(Node.java:424) at javafx.scene.Node.impl_markDirty(Node.java:415) at javafx.scene.shape.Shape.impl_markDirty(Shape.java:942) at javafx.scene.shape.Circle$1.invalidated(Circle.java:136) at javafx.beans.property.DoublePropertyBase.markInvalid(DoublePropertyBase.java:112) at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:146) at javafx.scene.shape.Circle.setCenterX(Circle.java:122) at Main$2.run(Main.java:48) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505)
我真的没有看到什么是错的
可能是因为你误解了Platform.runLater()
是如何工作的。
正确的代码段是:
public void moveCircle(Circle circle, Scene scene) { Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { Platform.runLater(() -> { circle.setCenterX(random((int) scene.getX())); circle.setCenterY(random((int) scene.getY())); }); } }, 1000, 1000); }
但:
我强烈建议你不要使用Timer
而是使用TimeLine
! 它是JavaFX API的一部分,您无需执行这些Platform.runLater()
调用。 这很快被黑客攻击,但你明白了:
public void moveCircle(Circle circle, Scene scene) { Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), ev -> { circle.setCenterX(random((int) scene.getX())); circle.setCenterY(random((int) scene.getY())); })); timeline.setCycleCount(Animation.INDEFINITE); timeline.play(); }