Javafx实时线程更新

Sim*_*ann 0 java multithreading javafx

我正在与Javafx和线程同时工作,我一直遇到这个问题,我做了一个按钮然后当点击按钮时(使用事件处理程序)我做了一个for循环,将按钮更改为1,2,3,4 ,5然后在每个中间延迟一秒钟.倒计时!

但是发生的事情是延迟5秒并将按钮文本更改为5.

问题是我希望看到它在1到5之间变化,但我看到的只有在5秒延迟结束时为5.我会认为它改变了按钮文本,但我没有看到它.我可能不得不.show()Javafx课堂上使用该方法.

public class HewoWorld extends Application implements EventHandler<ActionEvent>
{
    Thread t = new Thread();
    Button butt;
    boolean buttWasClicked = false;
    Circle circ1 = new Circle(40, 40, 30, Color.RED);
    Circle circ2 = new Circle(100, 100, 30, Color.BLUE);
    Group root;
    Scene scene;
    Stage disStage = new Stage();
    int i = 1;
    public static void main(String[] args)
    {
        launch(args);
    }
    public void start(Stage stage) throws Exception 
    {

        disStage.setTitle("tests stuffs");
        Screen screen = Screen.getPrimary();
        Rectangle2D bounds = screen.getVisualBounds();
        double windh = bounds.getHeight()/2+150;//sets height of screen 
        double windw = bounds.getWidth()/3;//sets width of screen 
        Pane layout = new Pane();
        butt = new Button();
        butt.setText("Hello world");


        root = new Group(circ1, circ2, butt);
        scene = new Scene(root, 800, 400);
        disStage.setWidth(windw);
        disStage.setHeight(windh);


        butt.setLayoutX(200);
        butt.setLayoutY(200);
        butt.setOnAction(this);
        disStage.setScene(scene);
        disStage.show();
    }
     public void handle(ActionEvent event) 
    {
        if (event.getSource() == butt && buttWasClicked == false) 
        {
            try
            {
                butt.setText(i+"");
                t.sleep(1000);
                i++;
            }
            catch(Exception q)
            {

            } 
            circ1 = new Circle(40, 40, 30, Color.BLACK);
            circ2 = new Circle(100, 100, 30, Color.RED);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*s_D 5

为什么你的代码不起作用

您的代码不起作用的原因是您正在阻止FX应用程序线程.

像(几乎?)所有UI工具包一样,JavaFX是一个单线程UI工具包.这意味着所有事件处理程序以及UI的所有呈现都在单个线程(称为FX应用程序线程)上执行.

在您的代码中,您有一个运行时间超过一秒的事件处理程序,因为它通过调用暂停一秒钟Thread.sleep(...).当该事件处理程序正在运行时,无法重绘UI(因为单个线程不能同时执行两项操作).因此,虽然按钮文本的值立即更改,但在handle(...)方法运行完毕之前,新值实际上不会在屏幕上呈现.如果for在handle方法中有一个循环,则在整个循环(以及方法中的任何其他内容)完成之前不会呈现任何内容.

如何解决它

在JavaFX中执行所需操作的最简单方法是使用a Timeline来处理暂停.在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);
    }
}
Run Code Online (Sandbox Code Playgroud)

一般情况下,用于改变所述用户接口的在特定时间点的外观,所述的JavaFX动画API(另见教程)可能是有用的,尤其是TimelinePauseTransition.

这样做的"低级"方法是创建一个Thread自己并在该线程中暂停.这是更先进的:您需要小心更新FX应用程序线程上的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

有关JavaFX中线程的更多常规信息,请查看以下文章:使用线程发出数据库请求