JavaFX Thread什么时候绘制到显示器?

时间:2015-07-21 16:17:14

标签: javafx java-8

我注意到Platform.runLater()在运行后没有立即更新舞台/屏幕,因此我猜测这幅画正在其他地方或其他排队的事件中发生。在运行完成后,我对在屏幕上实际绘制或渲染的时间或方式排队或发出信号感到好奇。

以下代码将1.begin, 1.end, 2.begin, 2.end, 3.begin, 3.end打印到控制台,但标签从不显示1,但第二个runLater()等待。

package main;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.concurrent.CountDownLatch;

public class SmallRunLater extends Application {

    SimpleStringProperty labelValue = new SimpleStringProperty("0");

    @Override
    public void start(Stage stage) throws InterruptedException {

        Scene scene = new Scene(new Group());
        stage.setWidth(550);
        stage.setHeight(550);

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));

        Label label = new Label();
        label.textProperty().bind(labelValue);
        Button startBtn = new Button("Start");
        vbox.getChildren().addAll(startBtn, label);

        startBtn.setOnAction((action) -> {
            try {
                Task task = new Task<Void>() {
                    @Override
                    protected Void call() throws Exception {
                        SmallWork work = new SmallWork();
                        work.doWork(labelValue);
                        return null;
                    }
                };
                new Thread(task).start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        ((Group) scene.getRoot()).getChildren().addAll(vbox);

        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

class SmallWork {

    public void doWork(SimpleStringProperty labelValue) throws InterruptedException {

        Platform.runLater(() -> {
            System.out.println("1.begin");
            labelValue.set("1");
            System.out.println("1.end");
        });

        runNow(() -> {
            System.out.println("2.begin");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            labelValue.set("2");
            System.out.println("2.end");
        });

        Platform.runLater(() -> {
            System.out.println("3.begin");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            labelValue.set("3");
            System.out.println("3.end");

        });
    }

    public static void runNow(Runnable r){

        final CountDownLatch doneLatch = new CountDownLatch(1);

        Platform.runLater(() -> {
            try {
                r.run();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                doneLatch.countDown();
            }
        });

        try {
            doneLatch.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

1 个答案:

答案 0 :(得分:3)

是的,你是对的,Platform.runLater()(如名称所示)不会立即运行,只是将Runnable推送到内部队列。内部渲染刻度深入。 Runnable对象将在渲染之前的更新标记中执行。标签从未显示&#34; 1&#34;简单地与你的runNow()被立即调用的事实相吻合,因此两个Runnable对象被推送到同一队列并在JavaFX内部循环内的相同时钟中执行。因此,会发生以下情况:

  1. 标签设置为1
  2. 内部线程设置为睡眠状态。如果您注意到,这实际上冻结了应用程序,因为渲染线程现在处于休眠状态
  3. 标签设置为2
  4. 渲染滴答,我们可以看到&#34; 2&#34;
  5. ...
  6. 我已尝试运行上面的代码,有时我可以看到1,这意味着两个Runnable对象被推入不同的刻度。这样的事情:

    1. 标签设置为1
    2. 渲染刻度
    3. ...