如何在javafx中获取对通过fx:id描述的节点的引用?

时间:2016-11-25 11:47:25

标签: javafx

我有一个简化的问题示例,其中fx:id的代码引用在调用initialize时不为空,但在函数调用后立即转到null。获得此类参考的正确方法是什么?这是sample.fxml

<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="sample.Main">
   <columnConstraints>
      <ColumnConstraints />
   </columnConstraints>
   <rowConstraints>
      <RowConstraints />
   </rowConstraints>
   <children>
      <Text fx:id="textRef" strokeType="OUTSIDE" strokeWidth="0.0" text="Hello world" />
   </children>
</GridPane>

这是Main.java,它被声明为其控制器。

public class Main extends Application implements Initializable{
    @FXML
    public Text textRef;

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();

        this.someNewFunction();
    }

    private void someNewFunction() {
        this.textRef.setText("Changed in somNewFunction");
    }


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

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        this.textRef.setText("Changed at initialize");
    }
}

文本引用在initialize调用中有效,但在someNewFunction内部时抛出nullpointerexception。

2 个答案:

答案 0 :(得分:3)

启动的Main实例与Main创建的用作控制器的FXMLLoader实例不同。

恕我直言,最好在加载fxml后从FXMLLoader获取控制器,并使用与Application不同的类作为控制器:

public class MainController implements Initializable {

    ...   

}
<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="sample.MainController">
   ...
</GridPane>
@Override
public void start(Stage primaryStage) throws Exception {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
    Parent root = loader.load();
    primaryStage.setTitle("Hello World");
    primaryStage.setScene(new Scene(root, 300, 275));
    primaryStage.show();

    MainController controller = loader.getController();

    controller.someNewFunction();
}

但是,您也可以指定应与fxml一起使用的控制器:

<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
   ...
</GridPane>
@Override
public void start(Stage primaryStage) throws Exception {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
    loader.setController(this);
    Parent root = loader.load();
    primaryStage.setTitle("Hello World");
    primaryStage.setScene(new Scene(root, 300, 275));
    primaryStage.show();

    this.someNewFunction();
}

答案 1 :(得分:0)

您正在javafx循环外执行someNewFunction。 我的意思是,在show方法结束后,主线程获得控制权并且javafx组件不再存在(它们被破坏,因为它们不再需要它们)。 你必须将someNewFunction绑定到一些连接到某些FXML元素引用的事件(即通过SceneBuilder上的setOnAction或通过代码的Button),将方法调用放在initialize方法中,或者只是在primaryStage.show之前移动调用( )线。

希望这有帮助