javafx - JavaFX 线程何时绘制到显示器上?

标签 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();
        }
    }
}

最佳答案

是的,你是对的,Platform.runLater()(如名称所暗示)不会立即运行,只是将Runnable推送到内部队列。深处有一个内部渲染标记。 Runnable 对象将在渲染之前的更新标记中执行。标签从不显示“1”的事实与您的 runNow() 在同一时间点内立即被调用的事实恰好吻合,因此两个 Runnable 对象被推送到同一队列并在 JavaFX 内部循环中的同一时间点中执行。因此,会发生以下情况:

  1. 标签设置为 1
  2. 内部线程设置为 sleep 状态。如果您注意到的话,这实际上会卡住应用程序,因为渲染线程现在正在休眠
  3. 标签设置为 2
  4. 发生渲染标记,因此我们可以看到“2”
  5. ...

我尝试运行上面的代码,有时我可以看到 1,这意味着两个 Runnable 对象被推送到不同的刻度中。类似这样的事情:

  1. 标签设置为 1
  2. 渲染勾选
  3. ...

关于javafx - JavaFX 线程何时绘制到显示器上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31544427/

相关文章:

java - 无法找到依赖项中的 Json 文件

JavaFX canvas GraphicsContext.drawImage 巨大的滞后

java - 制作一个jar文件,应用程序被java安全阻止

java - 修改部分列表,然后返回更新后的列表

java - 给定字符集将 InputStream 转换为 Stream<String>

java-8 - 在java8中如何仅使用自定义代码定义函数?

JavaFx:使用加法/乘法/双向绑定(bind)数字

javafx - 如何使用 JavaFX 为未装饰的舞台添加阴影?

java - JavaFX 中的彩色图标字体

java-8 - 收藏集与加入Java 8