为什么你的代码不起作用
您的代码不起作用的原因是您阻塞了 FX 应用程序线程。
像(几乎?)所有 UI 工具包一样,JavaFX 是一个单线程 UI 工具包。这意味着所有事件处理程序以及所有 UI 渲染都在单个线程(称为 FX 应用程序线程)上执行。
在您的代码中,您有一个事件处理程序需要超过一秒的时间才能运行,因为它通过调用暂停了一秒钟Thread.sleep(...)
。当该事件处理程序运行时,无法重绘 UI(因为单个线程无法同时执行两件事)。因此,虽然按钮文本的值已立即更改,但新值实际上不会在屏幕上呈现,直到handle(...)
方法已完成运行。如果你有一个for
循环句柄方法中,在整个循环(以及方法中的其他任何内容)完成之前不会呈现任何内容。
如何修复它
在 JavaFX 中执行您想要的操作的最简单方法是使用Timeline http://docs.oracle.com/javase/8/javafx/api/javafx/animation/Timeline.html来处理暂停。这Timeline
为您适当管理线程:
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class CountingButton extends Application {
@Override
public void start(Stage primaryStage) {
Button button = new Button("Count");
Timeline timeline = new Timeline();
for (int count = 0; count <= 5 ; count++) {
final String text = Integer.toString(count);
KeyFrame frame = new KeyFrame(Duration.seconds(count), event ->
button.setText(text));
timeline.getKeyFrames().add(frame);
}
button.setOnAction(e -> timeline.play());
primaryStage.setScene(new Scene(new StackPane(button), 120, 75));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
一般来说,为了在特定时间点改变用户界面的外观,JavaFX 动画 API http://docs.oracle.com/javase/8/javafx/api/javafx/animation/package-summary.html(另请参阅tutorial http://docs.oracle.com/javase/8/javafx/visual-effects-tutorial/animations.htm#JFXTE149)可能很有用,特别是Timeline
and PauseTransition http://docs.oracle.com/javase/8/javafx/api/javafx/animation/PauseTransition.html.
执行此操作的“较低级别”方法是创建一个Thread
你自己并在该线程中暂停。这要高级得多:您需要小心更新 FX 应用程序线程上的 UI,而不是您创建的线程上的 UI。您可以通过致电来完成此操作Platform.runLater(...)
:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class CountingButton extends Application {
@Override
public void start(Stage primaryStage) {
Button button = new Button("Start");
button.setOnAction(e -> {
Thread thread = new Thread(() -> {
for (int i = 0; i <= 5 ; i++) {
final String text = "Count: "+i ;
Platform.runLater(() -> button.setText(text));
try {
Thread.sleep(1000);
} catch (InterruptedException exc) {
exc.printStackTrace();
}
}
});
thread.start();
});
primaryStage.setScene(new Scene(new StackPane(button), 120, 75));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
有关 JavaFX 中线程的更多一般信息,请查看这篇文章:使用线程发出数据库请求 https://stackoverflow.com/questions/30249493/using-threads-to-make-database-requests/30250308#30250308