javafx fxml在initialize()之外为null

时间:2013-07-13 22:01:05

标签: javafx fxml

在此代码中:

public class ESM extends Application {

private Stage primaryStage;

@FXML 
private ToolBar mainToolBar;


@Override
public void start(final Stage stage) throws Exception {
    try{
        this.primaryStage = stage;
        Parent root = FXMLLoader.load(getClass().getResource("/nz/co/great_ape/esm3/main_window.fxml"));

        Scene scene = new Scene(root, 800, 700);            
        //  Setup main stage to be full screen, no min or max buttons.
        //  TODO:  How will this handle multiple screens?  Apparently not well :-(
        Screen screen = Screen.getPrimary();
        Rectangle2D bounds = screen.getVisualBounds();
        primaryStage.setX(bounds.getMinX());
        primaryStage.setY(bounds.getMinY());
        primaryStage.setWidth(bounds.getWidth());
        primaryStage.setHeight(bounds.getHeight());
        primaryStage.initStyle(StageStyle.UNDECORATED); 
        primaryStage.setTitle("ESM three");
        primaryStage.setScene(scene);
        primaryStage.show();
        System.out.println("This will fail because mainToolBar is null.  Why?");
        assert mainToolBar != null : "fx:id=\"mainToolBar\" was null check your FXML ";
    } catch (Exception ex) {
        Logger.getLogger(ESM.class.getName()).log(Level.SEVERE, null, ex);
    }           
}



/**
 * Use initialize() to setup widgets from scenebuilder files, it is
 * called by FXMLLoader.
 */
@FXML
public void initialize(){
    System.out.println("initialize() But when here all is good and mainToolBar is a ToolBar.");
    assert mainToolBar != null : "fx:id=\"mainToolBar\" was null check your FXML ";     
}

/**
 * The main() method is ignored in correctly deployed JavaFX application.
 * main() serves only as fallback in case the application can not be
 * launched through deployment artifacts, e.g., in IDEs with limited FX
 * support. 
 *
 * @param args The command line arguments.
 */
public static void main(String[] args) {
    launch(args);

}

}

我无法理解为什么它在initialise()中有一个值,但在开始时它是null。在调试时很明显,FXMLLOader从start()内部调用initiialize()

我打算发布fxml,但它似乎不能用作预览中的nothig节目。无论如何,它是一个真正的基本文件,BordePane和ToolBar。

任何线索?

1 个答案:

答案 0 :(得分:6)

始终为FXML Controller创建一个新类,不要尝试将Application类重用为Controller类。

应用程序实例由JavaFX应用程序启动器创建。

Controller实例由JavaFX FXML加载程序创建。

您没有提供您使用的FXML,但我猜测它的Controller类被错误地设置为您的应用程序类。

所以在你的代码中,会发生什么:

  1. 运行程序时(通过启动方法)创建应用程序实例。
  2. 在您的应用程序启动方法中,您调用FXMLLoader,它实例化一个新的Controller(在您的情况下是一个新的应用程序类的实例)。
  3. FXMLLoader将@FXML标记的成员注入 new 应用程序对象,并调用 new 对象的初始化。
  4. 但您的原始应用程序对象对新应用程序对象一无所知,因此没有设置菜单栏。
  5. 总之,要解决这个问题:

    1. 创建一个FXMLLoader可以实例化的新控制器类。
    2. 更改您的fxml以引用新的控制器类。
    3. 如果您的应用程序确实需要引用控制器,那么您可以在FXML加载器上使用getController方法,并在控制器类中提供检索所需元素的公共方法(如菜单栏)。有关此方法的更多示例,请参阅我对Passing Parameters JavaFX FXML的回答。

      import javafx.scene.control.ToolBar;
      import javafx.fxml.FXML;
      
      public class ESMController {
        @FXML 
        private ToolBar mainToolBar;
        public  ToolBar getMainToolBar() { return mainToolBar; }
      
        @FXML
        public void initialize(){
          assert mainToolBar != null : "fx:id=\"mainToolBar\" was null check your FXML ";     
        }
      }