JavaFX 如何访问 Controller 中的 Application 对象?

JavaFX How can I access Application object in Controller?

我正在创建一个简单 javaFX 程序。在 HelloApplication 中,我想做逻辑,在 HelloController 中,我想听按钮点击,然后在 HelloApplcation.

中执行方法

HelloApplication.java:

Timeline timeline;
@FXML
HelloController HC;
FXMLLoader fxmlLoader;
private int counter=0;
public void start(Stage stage) throws IOException {
        fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));

        Scene scene = new Scene(fxmlLoader.load(), 640, 480);
        stage.setTitle("Program!");
        stage.setScene(scene);
        stage.show();
        StartCounter("start");
}
public void StartCounter(String status)
    {
        HC = fxmlLoader.getController();
        if(timeline==null) {
            timeline = new Timeline(new KeyFrame(Duration.seconds(1), ev -> {
                HC.getCmd().setText(String.valueOf(counter));
                counter++;
            }));
            timeline.setCycleCount(Animation.INDEFINITE);
        }else{
            if(status=="stop")
                timeline.stop();
            else if(status=="start")
                timeline.play();
        }
}

HelloController.java:

  HelloApplication helloApp=new HelloApplication(); //this creates another instance...
 @FXML
    protected void onHelloButtonClick() {
        helloApp.StartCounter("stop");
    }

但是如何访问在 launch() 上创建的 HelloApplication 对象? 像 loader.getApplication() 这样的东西比在控制器中创建一个新对象更完美(无论如何都不起作用)。

现在,鼠标点击后 helloApp.StartCounter() 导致: java.lang.reflect.InvocationTargetException

如何访问Controller中的Application对象?

直接回答你的问题。

  1. 将应用程序实例保存到应用程序 init 方法中的静态变量。
  2. 提供静态访问器方法来访问它。

这有点像单例模式,但应用程序实例是由 launch 方法创建的。

public class AccessibleApp extends Application {
    private static AccessibleApp applicationInstance;

    public static AccessibleApp getApplicationInstance() {
        return applicationInstance;
    }

    @Override
    public void init() {
        applicationInstance = this;
    }

    // other app functionality ...

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

然后可以从任何 class 使用以下方式访问应用程序:

AccessibleApp.getApplicationInstance()

您的示例代码和方法存在问题

  1. 您不应创建另一个应用程序实例。

    application lifecycle javadoc 指出 JVM 中应该只有一个应用程序实例,这将通过调用 launch() 方法来创建。

    launch()方法只能为JVM进程调用一次。

  2. 应用程序中永远不应有 @FXML 注释 class。

    @FXML仅在控制器中使用,应用程序class不应该也是控制器。

  3. 您的整体做法不正确:

    in HelloController I want to listen to button clicks which then execute methods inside the HelloApplcation

    你不应该这样做。

    应用程序class负责应用程序的生命周期。除非它是一个普通的 self-contained hello world 风格的应用程序,否则它不应该做任何其他事情。它绝对不应该为 fxml 控制器回调提供服务。

推荐方法

直接在控制器或专用服务中执行您的应用程序逻辑class。

  1. 写一个计数器 class,它有一个整数 属性 作为计数器值和一个时间线。
  2. 在 class 上提供启动和停止方法,不要为此使用字符串状态。
  3. 在控制器中创建一个 Counter 实例并在用户交互时启动和停止它。
  4. 在控制器初始化方法中,到计数器值。

与其尝试调试和修复您当前的代码,我建议您改为实施建议的方法。

要进一步了解此类方法,请参阅: