当前位置: 首页 > 面试题库 >

将引用传递给javafx.application.Application

马博学
2023-03-14
问题内容

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

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

我的问题是关于 JavaFx gui 添加
到此类应用程序。将GuiApp明显延长javafx.application.Application,将需要一个参考Model对象。

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

  • 静态方法:例如,已Business初始化对Modelin 的静态引用GuiApp。在这里可以看到使用静电的一个示例。

  • JavaFx 9方法:如此处所示 ,您无需扩展即可启动JavaFx应用程序Application

  • 更改工作流程方法:将现有工作流程更改为具有GuiApp initialize BusinessApp。这种工作流程的一个示例可以在此处看到。

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


问题答案:

我将尝试演示在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 答案所示,从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;
    }
}


 类似资料:
  • 问题内容: 我是android新手,非常习惯于网络开发。在javascript中,当您要执行异步任务时,可以将函数作为参数传递(回调): 我想知道我们是否可以对android进行相同的操作,将函数引用传递给方法,然后它将运行它。 有什么建议 ? 问题答案: 是的,回调的概念在Java中也非常存在。在Java中,您可以这样定义一个回调: 人们通常会在这样的内部嵌套这些侦听器定义: 回调的完整实现如下

  • 考虑这个简单的程序: 当我写的时候,我希望得到: 13 42 13 42 13 42 但是我得到的是: 13 42 0 42 0 42 当然,问题在于通过引用来吸收最后2个参数。因此,如果它们中的任何一个碰巧在正在操作的范围内,则结果可能是意外的。我可以通过添加一个临时变量来解决这个问题: 我知道C 11为我们提供了各种类型的工具,我是否可以简单地将这个值强制为非引用类型并内联传递,而不创建临时类

  • 问题内容: 我有一个使用while循环创建的按钮。所以while循环为mysql表中的每一行创建一个表行。 我为该按钮编写了一行代码,该代码针对表的每一行再次创建,并且每个按钮基于该记录具有不同的值。 问题是我想使用它并以模式查看它,以便可以使用mysqli查询检索具有相同ID的记录。 这是模态的代码。 问题答案: 如果可以,我对你是正确的。 模态触发按钮 Bootstrap Modal事件以使用

  • 问题内容: 我试图将SharedPreferences首选项作为AsyncTask中doInBackground函数的参数传递。我已经给它传递了一个字符串(URL),所以我也需要将首选项也作为字符串传递。我可以简单地使用prefs.toString()将其转换为字符串吗? 这是我设置偏好的地方: 问题答案: 你不能,你不应该。您可以轻松地读取内部首选项,而无需将任何内容传递给方法,只需使用即可:

  • 问题内容: 我正在尝试执行一个Web服务,该服务返回带有以下代码的DataTable: 如果Web服务返回一个类,则它将起作用,因此它与输入参数等无关。仅当Web方法返回一个数据表(该数据表仅包含2列和2行用于我正在执行的测试)时,它才会失败。 WebService类装饰有[ScriptService]属性,因此我认为ASP.NET将自动将返回值序列化为JSON。它似乎不适用于数据表。 我发现的唯

  • 问题内容: 我正在使用Go内置的http服务器,并拍拍来响应一些URL: 我需要向该处理函数传递一个额外的参数-一个接口。 如何向处理程序函数发送额外的参数? 问题答案: 通过使用闭包,您应该能够做您想做的事情。 更改为以下内容(未测试): 然后对