首页 > 解决方案 > 传递对 javafx.application.Application 的引用

问题描述

考虑一个非 fx 现有应用程序,我们称之为Business.

Business公开一个Model对象,该对象又公开一些属性。Model还接受这些属性的侦听器。

我的问题是关于 JavaFx gui 添加到此类应用程序中。GuiApp显然扩展javafx.application.Application并且需要对对象的引用Model

寻找将非字符串参数传递给我的解决方案,GuiApp我发现了几种不同的方法:

还有其他可行的方法吗?最佳实践 ?

标签: javajavafxjavafx-9

解决方案


我将尝试演示一些在 java 程序和 java-fx 程序之间传递引用的不同方法。
我发布它是希望它能帮助一些有类似需求的未来读者。我也希望它可以通过其他解决方案鼓励其他答案。
发布的代码不应被视为正确的实现,而是旨在阐明不同方法的简短代码。为此,我将介绍一个简单的监听界面:

interface Observe{ void update(int i); }

一个 java 类,代表一个现有的业务应用程序:

public class JavaApp {

    private Observe observer;  private int counter = 0;

    JavaApp(Observe observer){  //not null safe
        this.observer = observer;
    }

    void process() {            
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                observer.update(counter >=100 ? 0 : ++counter);
            }
        }, 1000,1000);
    }
}

应添加到现有业务应用程序中的 java-fx 应用程序,监听它并用作视图:

public class JavaFxApp extends Application implements Observe{

    private Label label;

    @Override public void start(Stage stage) {
        label = new Label("waiting");
        BorderPane pane = new BorderPane(label);
        Scene scene = new Scene(pane, 100, 100);
        stage.setScene(scene);
        stage.show();
    }

    @Override public void update(int i) {
        Platform.runLater(()-> label.setText(String.valueOf(i)));
    }
}

我们如何Observe在两个应用程序之间共享引用,在这种情况下是对实例的引用?

方法 1:将start()方法视为应用程序的入口点(请参阅 James_D答案
如果您想将现有的 java 应用程序与 java-fx 绑定并使用 java-fxApplication作为入口点,这很简单:

public class JavaFxApp extends Application implements Observe{

    private Label label;

    @Override public void start(Stage stage) {  
        JavaApp main = new JavaApp(this);
        label = new Label("waiting");
        BorderPane pane = new BorderPane(label);
        Scene scene = new Scene(pane, 100, 100);
        stage.setScene(scene);
        stage.show();

        new Thread(()-> { main.process();}).start(); //launch the business process
    }

    @Override   public void update(int i) {
        Platform.runLater(()-> label.setText(String.valueOf(i)));
    }

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


方法 2:使用 JavaFX 9 Platform#startup
这是我找到的最佳解决方案,当您不能使用该Application#start方法作为应用程序的入口点时。
正如 fabians answer中所展示的,作为 off java-fx 9,您可以在不扩展的情况下启动Application. 您所要做的就是修改mainjava 应用程序的:

public class JavaApp {

    private Observe observer;  private int counter = 0;

    JavaApp(Observe observer){//not null safe
        this.observer = observer;
    }

    void process() {
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override   public void run() {
                observer.update(counter >=100 ? 0 : ++counter);
            }
        }, 1000,1000);
    }

    public static void main(String[] args) {
        JavaFxApp view = new JavaFxApp(); //initialize JavaFx application
        JavaApp main = new JavaApp(view);

        Platform.startup(() -> {//launch JavaFx application 

            Stage stage = new Stage();
            try {
                view.start(stage);
            } catch (Exception ex) {ex.printStackTrace();}
        });

        main.process(); //run business process 
    }
}


方法 3:使用静态成员
例如在 java-fx 应用程序中引入静态 getter:

public class JavaFxApp extends Application {

    private static Label label = new Label("waiting");

    @Override public void start(Stage stage) {  
        BorderPane pane = new BorderPane(label);
        Scene scene = new Scene(pane, 100, 100);
        stage.setScene(scene);
        stage.show();
    }

    static Observe getObserver() {
        return JavaFxApp::update;
    }

    private static void update(int i) {
        Platform.runLater(()-> label.setText(String.valueOf(i)));
    }
}

并在java应用程序中使用它:

public class JavaApp {

    private Observe observer;  private int counter = 0;

    JavaApp(Observe observer){//not null safe
        this.observer = observer;
    }

    void process() {
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                observer.update(counter >=100 ? 0 : ++counter);
            }
        }, 1000,1000);
    }

    public static void main(String[] args){
        new Thread(()-> Application.launch(JavaFxApp.class)).start();
        Observe observer = JavaFxApp.getObserver(); //get static observer reference
        JavaApp main = new JavaApp(observer);
        main.process();
    }
}

获得静态引用的更好方法可能是(基于答案):

public class JavaFxApp extends Application implements Observe{

    private static final CountDownLatch latch = new CountDownLatch(1);
    private static Observe observer = null;
    private Label label;

   @Override public void init() {
       observer = this;
       latch.countDown();
    }

    @Override public void start(Stage stage){
        label = new Label("waiting");
        BorderPane pane = new BorderPane(label);
        Scene scene = new Scene(pane, 100, 100);
        stage.setScene(scene);
        stage.show();
    }

    @Override public void update(int i) {
        Platform.runLater(()-> label.setText(String.valueOf(i)));
    }

    static Observe getObserver() {
        try {
            latch.await();
        } catch (InterruptedException e) { e.printStackTrace();  }

        return observer;
    }
}

推荐阅读