ScalaFX(或 JavaFX)- 多次从另一个主要 class 调用 GUI

ScalaFX (or JavaFX) - Calling GUI from another main class multiple times

我在继续上一个问题:

我想做的是为这个模拟包创建一个类似 matplotlib 的包。我设想的最终用途看起来像 matplotlib:

import matplotlib.pyplot as plt

plt.plot([1, 2, 3, 4])
plt.ylabel('some numbers')
plt.show()

plt.plot([10, 20, 3000, 4121212])
plt.ylabel('some numbers')
plt.show()

对于我的包裹,我会做类似的事情。这里假设 myFXPackage 是一个用 ScalaFX 编写的图表包。在我的驱动程序中 class:

Import myFXPackage
// run some simulation code here...
myFXPackage.plot(results)

// run some MORE simulation code here...
myFXPackage.plot(results)

现在看来,对于ScalaFX,整个应用只能有一个入口点;这是 JFXApp class。但是,我想在我的 DRIVER class 中多次导入包并简单地 运行 这段代码,如上所示。所以不知何故 DRIVER class 将如何调用 ScalaFX 和 运行 情节,关闭它,然后 运行 另一个情节。

这可行吗?如果是这样,我该怎么做呢?

大多数 JavaFX 示例代码将 main 方法与 Application subclass 方法混为一谈,在许多情况下甚至会在相同 class。不一定有这样做的理由,在后一种情况下,这不是一个特别好的设计。

假设您在 UI 代码中适当地分离关注点,您可能有一个 class 像

public class MainUI {

    private BorderPane root ;

    public MainUI() {
        root = new BorderPane();
        // do layout, register event handlers, etc etc
    }

    public Pane getView() {
        return root ;
    }
}

然后如果你想要一个独立的 JavaFX 应用程序,你会做

public class JavaFxApp extends Application {

    @Override
    public void start(Stage stage) {
        MainUI ui = new MainUI();
        Scene scene = new Scene(ui.getView());
        stage.setScene(scene);
        stage.show();
    }

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

但这不是您可以使用 UI class 的唯一地方。在 JavaFX 中(与大多数 UI 工具包一样),您 必须 创建一个新阶段,并在 UI 线程上执行其他 UI 任务(即 FX 应用程序线程)。

此外,在 JavaFX 中,您必须显式启动 FX 工具包。在上面的代码中,这是通过 Application.launch() 方法完成的。

JavaFX 9 引入了一个 Platform.startup(Runnable),它启动 FX 工具包并在 FX 应用程序线程上执行提供的 Runnable

因此,使用 JavaFX 9 及更高版本,您可以拥有类似

的代码
public class SomeApp {

    public static void main(String[] args) {
        // start FX toolkit
        // Since we don't want it to exit when we close a window, set 
        // implicit exit to false:
        Platform.startup(() -> Platform.setImplicitExit(false));

        // do some other stuff...

        // whenever you need to:
        Platform.runLater(SomeApp::showStage);

        // do other stuff...
    }

    private static void showStage() {
        Scene scene = new Scene(new MainUI().getView());
        Stage stage = new Stage();
        stage.show();
    }
}

在 JavaFX 9 之前,您仍然可以这样做,但是您需要启动一个 "blank" 应用程序:

public class FXStartup extends Application {

    @Override
    public void start(Stage ignored) {
        // probably need this:
        Platform.setImplicitExit(false);
    }
}

请注意,launch() 方法会阻塞,直到工具包退出,因此您的应用程序需要在另一个线程中启动它:

public class SomeApp {

    public static void main(String[] args) {
        // start FX toolkit
        new Thread(() -> Application.launch(FXStartup.class, args)).start();

        // do some other stuff...

        // whenever you need to:
        Platform.runLater(SomeApp::showStage);

        // do other stuff...
    }

    private static void showStage() {
        Scene scene = new Scene(new MainUI().getView());
        Stage stage = new Stage();
        stage.show();
    }
}