无法在 JavaFX 项目中实例化 class 个字段

Can't instantiate class fields in JavaFX project

所以我试图从 Swing 转移到 JavaFX,我只是声明了 start()launch() 方法,而不知道它们是如何工作的。但是下面的代码将 false 和 false 打印到控制台。然而,当我单击 GUI 中的按钮时,使用 Scene Builder 构建,执行 myMethod(),这次它打印 true。为什么说 primaryStage 没有被实例化?

补充信息: 出于同样的原因,我也将此 class 作为我的控制器 - 它需要访问 Stage 引用。如果重要的话,我没有 post 的完整版 Main 实现了 Initializable

作为奖励问题 我想知道我是否需要 primaryStage 的字段来引用申请阶段,其中只有一个?,在 myMethod().

public class Main extends Application {

    private Stage primaryStage;

    public void start(Stage primaryStage) {
        this.primaryStage = primaryStage;
        try {
            Scene scene = new Scene(FXMLLoader.load(getClass().getResource("Sample.fxml")),600,400);
            primaryStage.setScene(scene);
        } catch(Exception e) {
            e.printStackTrace();
        }
        primaryStage.show();
        //both lines below print false; As they should.
        System.out.println(this.primaryStage == null);
        myMethod();
    }

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

    public void myMethod() {
        System.out.println(primaryStage == null);
    }
}

编辑

将此 FXML 文档放在与上面相同的文件夹中 class 将让您 运行 Main 看到按钮确实打印 true。

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<HBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Main">
   <children>
      <Button mnemonicParsing="false" onAction="#myMethod" text="Button" />
   </children>
</HBox>

这是因为 FXMLLoader 将创建 application.Main class 的新实例,其中 start() 方法未被调用,因此 private Stage primaryStage 是空。

FXML的主class和controller还是分开比较好,必要的时候再过初级:

...
try
{
    FXMLLoader loader = new FXMLLoader( getClass().getResource( "Sample.fxml" ) );
    Scene scene = new Scene( loader.load(), 600, 400 );

    ( (MyController) loader.getController() ).setPrimaryStage(primaryStage);
    primaryStage.setScene( scene );
}
catch ( Exception e )
{
    e.printStackTrace();
}
...

其中 MyController class 可以简单为:

public class MyController {

    private Stage primaryStage;

    public void setPrimaryStage(Stage primaryStage) {
        this.primaryStage = primaryStage;
    }
}

还可以实现Initializable interface. Refer to Introduction to FXML :: Controllers.

另请注意,您可以通过以下方式从构成该场景图(即显示的舞台)的任何节点获取场景及其舞台:

Scene scene = anynode.getScene();
Stage primaryStage = (Stage) anynode.getScene().getWindow();

当然,对于您创建的次要阶段,getWindow() 将 return 该阶段而不是主要阶段。

根本不需要跳过任何这些环圈就可以访问 window。您可以在任何节点上调用 getScene().getWindow() 以获取显示它的 window (当然您可以以通常的方式将任何节点注入您的控制器)。

不要使用 Application subclass 作为控制器 class:你将有(至少)两个不同的实例(一个由 launch()方法,因为它是 Application subclass,并且由 FXMLLoader 创建,因为它是控制器 class)。不同的实例会初始化不同的字段。

创建控制器class,并向其中至少注入一个节点:

public class Controller {

    @FXML
    private Parent root ;

    @FXML
    private void myMethod() {
        Window window = root.getScene().getStage();
        // assuming you are running as a standalone application, the window 
        // will actually be a Stage instance.

        window.hide();  // for example...
    }
}

将其用作您的控制器class并将节点注入其中:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<HBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller" fx:id="root">
   <children>
      <Button mnemonicParsing="false" onAction="#myMethod" text="Button" />
   </children>
</HBox>