【问题标题】:Multithreaded JavaFX UI多线程 JavaFX 用户界面
【发布时间】:2019-03-18 08:31:51
【问题描述】:

我有两个相互交织的多线程问题。

我在使用 Spring Boot 的 JavaFX 桌面应用程序中有一个 SplitPane。左边是 TreeView,右边是 TabPane。一开始,SplitPane 分隔符位于隐藏 TabPane 的右边缘。当用户在树中选择一个项目时,两件事将并行发生:

首先,根据选择创建约 10 个选项卡。选项卡因所选对象而异。每个选项卡显示与所选对象相关的详细数据。大多数选项卡包含图表,但也包含文本。

其次,由于选项卡的设置需要几秒钟 - 需要从数据库中获取数据 - 想法是将 TabPane 分隔符缓慢“滚动”到左侧,隐藏树。这给用户一种应用程序仍在运行的印象,并使过渡更加柔和。我不喜欢等待,等待,......砰!

一个问题是,我正在使用的时间线(见下文)卡顿,我无法让它无缝地并行工作以设置选项卡。

标签的创建在专用任务中运行,每个标签创建者都使用Platform.runLater()。第二个麻烦是,我不确定这是否是最好的编码方式。我的意思是,几乎所有选项卡都被顶部隐藏,但所有选项卡都是在应用程序线程中一个接一个地创建的。

换句话说,伪代码看起来像这样:

KeyValue keyValue = new KeyValue(splitPane.getDividers().get(0).positionProperty(), 0.1);
Timeline timeline = new Timeline(new KeyFrame(Duration.millis(300), keyValue));
timeline.play();

Task task = new Task<Void>() {
    @Override public Void call() {
       Platform.runLater(()-> {
           createTabA();
       }

       ..

       Platform.runLater(()-> {
           createTabZ();
       }

       return null;
    }
};
Thread thread = new Thread(task);
thread.setDaemon(true);
thread.start();

我还更改了顺序,在启动线程后有时间轴。它看起来有所不同,但仍不如预期。

我怎样才能改进我的多线程逻辑并摆脱这种扭曲?

顺便说一句:在实际代码中,我已经在此过程运行时更改了光标,以使其更易于用户理解。

提前谢谢你!

【问题讨论】:

标签: multithreading user-interface javafx


【解决方案1】:

Runnables 传递给 Platform.runLater 在 JavaFX 应用程序线程上运行,并从后台线程快速连续使用多个 Platform.runLater 调用具有 JavaFX可以决定做的唯一好处Tab 创作之间的布局。选项卡的创建没有得到更快的速度。

传递给Platform.runLaterRunnables 不应包含任何长时间运行的操作。

而是在后台线程上创建选项卡但不要将它们附加到来自该线程的场景。(在后台线程上创建(部分)场景只要您不修改附加到 Scene 的内容,这不是问题。)

如果您可以在任务结束时一次添加所有选项卡,请考虑使用 Task&lt;List&lt;Tab&gt;&gt; 并返回选项卡。

Task<List<Tab>> task = new Task<List<Tab>>() {
    @Override public List<Tab> call() {
       List<Tab> result = new ArrayList<>(1 + 'Z' - 'A');

       for (char c = 'A'; c <= 'Z'; c++) {
           result.add(createTab(c));
       }

       return result;
    }
};
task.setOnSucceeded(evt -> tabPane.getTabs().addAll(task.getValue()));
...

否则在后台线程上创建Tabs,但将它们添加到应用程序线程上的TabPane

Task<Void> task = new Task<Void>() {
    @Override public Void call() {
       for (char c = 'A'; c <= 'Z'; c++) {
           final Tab tab = createTab(c);
           Platform.runLater(() -> tabPane.getTabs().add(tab));
       }

       return null;
    }
};

【讨论】:

  • 感谢您的反馈。 TabPane 及其所有选项卡已预先定义并加载为 fxml。我只获取数据,然后“填充”文本字段、图表等。所以选项卡已经附加到场景图中。当它们是场景图的一部分时,我可以打开/关闭元素吗?使用 setVisible() 就足够了吗?提前谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-03
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-08
相关资源
最近更新 更多