将Javafx 8 GUI与剩余代码

时间:2015-08-11 16:51:39

标签: javafx-8

在阅读javafx 8教程时,这似乎是主要的工作流程:

public class Test extends Application{
    public static void main(String[] args){
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader fxmlLoader = new FXMLLoader(TestFXController.class.getResource("test.fxml"));
        Parent root;
        try {
            root = fxmlLoader.load();
            Scene scene = new Scene(root, 1200, 800);
            primaryStage.setScene(scene);
            primaryStage.show();
            TestFXController controller = fxmlLoader.getController();
            controller.plotSomething();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

假设我有一个我想要运行的算法。在启动上述应用程序后,我可能会得到一个包含“运行算法”按钮的界面。按下按钮后,动作处理程序将调用该算法。 然后我有:启动java应用程序 - >构建界面 - >按按钮解算算法 - >显示解决方案所有将图形内容与算法分开的是一个按钮。事实上,图形界面“驱动”应用程序,因为它负责启动算法。 我更喜欢的是这样的事情:

public class Test2{
    public void main(String[] args){
        Algorithm alg=new Algorithm();
        alg.solve();
        GUI gui =new GUI(); //Spawns a Javafx 8 Graphical User Interface
        gui.displaySolution(alg.getSolution());
    }
}

对我而言,这似乎更清洁了?我不知道如何用javafx 8做这个,或者这是否可能?任何示例或参考都受到高度赞赏。我应该在GUI类中放置什么以便启动javafx 8接口? Test2中的示例还开辟了使用干净的观察者设计模式的可能性:

public class Test3{
    public void main(String[] args){
        Algorithm alg=new Algorithm();
        alg.addListener(new GUI()); //Add a Javafx 8 GUI as a listener.
        alg.addListener(new TextualLogger());
        alg.solve();
    }
}

请注意,在Test2和Test3类中,GUI不再驱动应用程序。

为了澄清,我的主要问题是:如果我在Test2中运行代码,那么GUI类的实现应该是什么?像这样:

public class GUI extends Application{

  public GUI(){
    //What should I put here? Perhaps launch(new String[]); ?
  }

  @Override
  public void start(Stage primaryStage) throws Exception {
    FXMLLoader fxmlLoader = new FXMLLoader(TestFXController.class.getResource("test.fxml"));
    Parent root;
    try {
    root = fxmlLoader.load();
    Scene scene = new Scene(root, 1200, 800);
    primaryStage.setScene(scene);
    primaryStage.show();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  public void displaySolution(Solution sol){
    ...
  }

}

3 个答案:

答案 0 :(得分:3)

在JavaFX应用程序中,您应该将start(...)方法视为“常规”Java应用程序中main(...)方法的等效方法。 (事实上​​,在Java 8中,JavaFX应用程序根本不需要main(...)方法。)引入了这种启动JavaFX应用程序的机制,以便尽可能地迫使程序员初始化UI在正确的线程上(与Swing相比,发布了大量代码,错误地启动了GUI)。为方便起见,start(...)方法在初始阶段通过,但如果您更喜欢使用不同的方法,则无需使用它。

所以你可以做到

public class Test2 extends Application {

    @Override
    public void start(Stage primaryStage) {
        Algorithm alg = new Algorithm();
        alg.solve();
        GUI gui = new GUI();
        gui.displaySolution(alg.getSolution());
    }

    // included for the benefit of IDEs that do not support
    // launching an Application without a main method:
    public static void main(String[] args) { launch(args); }
}

现在GUI不是Application子类(这是有道理的,因为它代表GUI,而不是应用程序):

public class GUI {

  public GUI(){

    FXMLLoader fxmlLoader = new FXMLLoader(TestFXController.class.getResource("test.fxml"));
    Parent root;
    try {
        root = fxmlLoader.load();
        Scene scene = new Scene(root, 1200, 800);
        Stage stage = new Stage();
        stage.setScene(scene);
        stage.show();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  public void displaySolution(Solution sol){
    ...
  }

}

这里要记住的一点是start(...)在FX应用程序线程上执行。因此,一旦显示了UI,就应该在后台线程上执行需要执行的任何进一步长时间运行的进程。在您描述的用例中,所有繁重的工作都是在显示UI之前完成的,所以这不是问题,但如果您尝试扩展此模式,则可能需要考虑这一点。

答案 1 :(得分:0)

我不确定我是否完全遵循您的尝试 - 您是否尝试打开第二个JavaFX窗口?

这样的事情会起作用吗?

Scene resultScene = algorithm.getSolution();
Stage resultStage = new Stage();
resultStage.setScene(resultScene);
resultStage.addEventHandler() or addEventFilter()
resultStage.show();

这个阶段可以是它自己的窗口或primaryStage的子窗口,这样如果你关闭父窗口,它也会关闭。

答案 2 :(得分:0)

如果你真的想从已经运行的第二个JavaFX窗口打开它。你可以参观。

Launch JavaFX application from another class

它将解决您的问题。

下面是如何运行新JavaFx应用程序的代码

        Platform.runLater(new Runnable(){
            @Override
            public void run(){
                new MainApp().start(new Stage()); // MainApp is the class name of your second Application
            }
        });

让您的类扩展Application并实现Runnable,并在该类中添加以下提及的代码

@Override
public void run(){
    launch();
}

将从run()方法调用launch()方法。不要在第二个类中使用Main()方法,否则抛出异常。