将引用传递给javafx.application.Application

时间:2018-10-26 07:38:45

标签: java javafx javafx-9

考虑一个非fx的现有应用程序,我们将其称为Business

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

我的问题是有关向该应用程序中添加 JavaFx gui。 GuiApp显然扩展了javafx.application.Application,将需要引用Model对象。

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

  • 静态方法:例如,让Business中的Model初始化对GuiApp的静态引用。可以使用here看到使用静态的一个示例。

  • JavaFx 9方法:如here所示,您可以在不扩展Application的情况下启动JavaFx应用程序。

  • 更改工作流程方法:更改现有工作流程以GuiApp初始化BusinessApp。可以here看到这种工作流程的一个示例。

还有另一种可行的方法吗?最佳实践 ?

1 个答案:

答案 0 :(得分:0)

我将尝试演示一些在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 answer
如果您想将现有的Java应用程序与java-fx绑定,并使用java-fx Application作为入口点,这将很简单明了:

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所示,从java-fx 9开始,您无需扩展Application就可以启动。您所需要做的就是修改Java应用程序的main

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();
    }
}

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

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;
    }
}