在一些外部事件之后切换javafx / jrubyfx场景

时间:2014-11-08 23:02:01

标签: java javafx jruby

我正在建模一个将使用JavaFX的原型。

该应用程序与自助服务终端类似,用于自助服务。但是在客户端与之交互之前,管理员应该将其解锁。管理员可以通过专用通道(HTTP或IPC或USB设备)发送一些远程命令。命令的示例包括:启动,停止和重置

我该怎么办?

a)我可以有一个任务,在另一个主动集中IPC的线程中运行,如果有消息,切换场景?

b)让一个反应器在一个线程中运行并且很快收到命令,它将它传递给JavaFX线程。

这两个选项都有效吗?确实存在第三个?

1 个答案:

答案 0 :(得分:1)

您的选项(a)具有Task的线程和(b)没有任务的线程都是有效的。

推荐的解决方案

我选择选项b(没有任务的线程)。

解决方案的关键部分是:

Platform.runLater(() -> MyApplication.changeScene(newData));

任务很好,但可能不适合您的情况

如果你有一些由UI或JavaFX线程启动的东西,那么任务就很好。例如,用户单击一个按钮,您希望根据该操作从服务器检索数据,在检索数据时通过消息和进度条更新反馈进度报告。因此,Task非常适合这种操作,因为它明确支持诸如消息反馈和进度更新之类的事情,以及任务开始和完成时定义良好的状态模型。请参阅不变量代码示例,以了解Task如何改进此类情况:Platform.runLater and Task in JavaFX

但是,当事件的发起者不在JavaFX应用程序线程中时,使用Task而不是使用传统的并发实用程序没有太大的优势。这是因为您通常不需要Task提供的额外服务,例如进度和消息更新API及其状态机。此外,启动此类事件的库通常已经拥有自己的线程模型设置,因此您不需要Task提供的额外线程框架。

使用Platform.runLater()

你真正想要的只是发生事情的通知。现在需要在JavaFX应用程序线程上进行通知,因为您无法使用另一个线程操纵活动场景中的项目。要将事件传递给JavaFX应用程序线程,请使用Platform.runLater(runnable)构造。

示例代码

我不会写Ruby,因为我真的不能,但是这里有一些Java代码可以为你提供要点 - 它实际上非常简单。

class DataReader implements Runnable {
    private final DataSource dataSource;

    public DataReader(String location) {
        dataSource = new DataSource(location);

        Thread thread = new Thread(this);
        thread.setDaemon(false);
        thread.start();
    }

    public void run() {
        while (dataSource.hasData()) {
            MyImmutableObject newData = dataSource.getSomeData();
            Platform.runLater(() -> MyApplication.changeScene(newData));
        }
    }
}

class MyApplication extends Application {
    public void changeScene(MyImmutableObject newData) {
        FXMLLoader loader = new FXMLLoader(
            getClass().getResource(
               "layout.fxml"
            )
        );

        UIController controller = 
            loader.<UIController>getController();
        controller.initData(newData);

        Scene scene = new Scene((Pane) loader.load());
        stage.setScene(newScene);
    }
}

上面的示例使用了虚构的DataSource,MyImmutableObject和UIController类以及虚构的FXML模板来演示这个概念(因此代码片段不是一个独立的可运行的东西)。 FXML加载概念来自:Passing Parameters JavaFX FXML。示例代码创建了自己的线程,但是如果您使用的库已经创建了线程(很可能),您不需要创建另一个线程,您可以使用Platform将适当的钩子添加到现有库中.runLater调用以获取事件通知以及在库线程和JavaFX应用程序之间传递数据。

相关问题

关于Platform.runLater与StackOverflow上的任务有很多其他问题:

其他问题

  在我的情况下,管理员在某些情况下能够向信息亭发送初始信息,几乎就像(初始化矢量),例如护照号码。有了这些信息,仍然是Platform.runLater的最佳解决方案吗?

是的,Platform.runLater仍然是最好的解决方案。当管理员将信息发送到信息亭时(例如,嵌入式http服务器或jax-rs服务上的servlet),您将有一些线程被警告,并且它可以调用Platform.runLater来更新基于JavaFX的信息亭UI。资讯