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

时间:2015-09-30 14:27:27

标签: java javafx scenebuilder

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

添加信息: 我也把这个类作为我的控制器,出于同样的原因 - 它需要访问舞台参考。如果重要的话,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文档放在与上一个类相同的文件夹中将允许您运行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>

2 个答案:

答案 0 :(得分:1)

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

最好将FXML的主类和控制器分开,如果有必要,稍后通过初级阶段:

...
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类可以如下所示:

public class MyController {

    private Stage primaryStage;

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

但也可以实现Initializable接口。请参阅Introduction to FXML :: Controllers

另请注意,您可以通过以下任意节点获取场景及其舞台,该节点是构建的场景图(即显示的舞台)的一部分:

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

当然,对于您创建的第二阶段,getWindow()将返回该阶段而不是主阶段。

答案 1 :(得分:1)

根本不需要跳过任何这些箍来访问窗口。您可以在任何节点上调用getScene().getWindow()以获取显示它的窗口(当然,您可以按照常规方式将任何节点注入控制器)。

不要使用Application子类作为控制器类:您将拥有(至少)两个不同的实例(一个由launch()方法创建,因为它是Application子类,以及FXMLLoader创建的一个,因为它是控制器类)。将在不同的实例中初始化不同的字段。

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

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

将此作为您的控制器类并将节点注入其中:

<?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>