代码之家  ›  专栏  ›  技术社区  ›  ihavenoidea

使用场景生成器8.0在JavaFX中使用setCenter()方法获取空指针异常

  •  0
  • ihavenoidea  · 技术社区  · 8 年前

    我创建了一个小程序来重现我在实际项目中遇到的错误。我有一个名为 MainWindow.java 这是两个原因。fxml文件: MainWindow.fxml 和 AnchorTest.fxml .

    控制器类的代码:

    package projecterror.controller;
    
    import java.io.IOException;
    
    import javafx.application.Application;
    import javafx.fxml.FXML;
    import javafx.fxml.FXMLLoader;
    import javafx.geometry.Rectangle2D;
    import javafx.scene.Scene;
    import javafx.scene.control.Menu;
    import javafx.scene.control.MenuItem;
    import javafx.scene.layout.AnchorPane;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Screen;
    import javafx.stage.Stage;
    
    public class MainWindow extends Application {
    
        private Stage primaryStage;
        private BorderPane mainWindow;
    
        @FXML
        Menu menuFile, menuAnalysis;
        @FXML
        MenuItem menuNew;
    
    
        @FXML
        private void initialize() {
            menuNew.setOnAction((event) -> {
                try {
                    FXMLLoader loader = new FXMLLoader();
                    loader.setLocation(getClass().getResource("../view/AnchorTest.fxml"));
                    AnchorPane anchorTest = (AnchorPane) loader.load();
                    mainWindow.setCenter(anchorTest);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    
        @Override
        public void start(Stage primaryStage) throws Exception {
            this.primaryStage = primaryStage;
            this.primaryStage.setTitle("Test Project");
    
            initMainWindow();
    
        }
    
        public void initMainWindow() {
            try {
                FXMLLoader loader = new FXMLLoader();
                loader.setLocation(getClass().getResource("../view/MainWindow.fxml"));
                mainWindow = (BorderPane) loader.load();
    
                Scene scene = new Scene(mainWindow);
                primaryStage.setScene(scene);
    
                //Fullscreen
                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.setResizable(false);
                primaryStage.show();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }
    

    主窗口。fxml 是一个 BorderPane 有一个 MenuBar 在…上 top .

    代码:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.control.Menu?>
    <?import javafx.scene.control.MenuBar?>
    <?import javafx.scene.control.MenuItem?>
    <?import javafx.scene.control.SeparatorMenuItem?>
    <?import javafx.scene.layout.BorderPane?>
    
    <BorderPane style="-fx-background-color: #DCDCDC;" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="projecterror.controller.MainWindow">
        <top>
          <MenuBar BorderPane.alignment="CENTER">
            <menus>
              <Menu fx:id="menuFile" mnemonicParsing="false" text="File">
                <items>
                      <Menu fx:id="menuAnalysis" mnemonicParsing="false" text="Analysis">
                        <items>
                          <MenuItem fx:id="menuNew" mnemonicParsing="false" text="New" />
                        </items>
                      </Menu>
                </items>
              </Menu>
            </menus>
          </MenuBar>
       </top>
    </BorderPane>
    


    主持人。fxml 是一个 AnchorPane 有两个孩子 锚烷 .

    代码:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import java.lang.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
    <?import javafx.scene.layout.AnchorPane?>
    
    <AnchorPane xmlns:fx="http://javafx.com/fxml/1">
        <children>
                <AnchorPane layoutX="6.0" layoutY="450.0" />
                <AnchorPane layoutX="6.0" layoutY="569.0" prefHeight="116.0" prefWidth="730.0">
                      <Button layoutX="6.0"   layoutY="26.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="102.0" text="Button 1" />
                      <Button layoutX="115.0" layoutY="26.0" mnemonicParsing="false" prefWidth="102.0" text="Button 2" />
                      <Button layoutX="226.0" layoutY="26.0" mnemonicParsing="false" prefWidth="102.0" text="Button 3" />
                      <Button layoutX="115.0" layoutY="75.0" mnemonicParsing="false" prefWidth="102.0" text="Button 4" />
                      <Button layoutX="383.0" layoutY="26.0" mnemonicParsing="false" prefWidth="102.0" text="Button 5" />
                      <Button layoutX="491.0" layoutY="26.0" mnemonicParsing="false" prefWidth="102.0" text="Button 6" />
                      <Button layoutX="600.0" layoutY="26.0" mnemonicParsing="false" prefWidth="102.0" text="Button 7" />
                      <Button layoutX="491.0" layoutY="75.0" mnemonicParsing="false" prefWidth="102.0" text="Button 8" />
                      <Button layoutX="600.0" layoutY="75.0" mnemonicParsing="false" prefWidth="102.0" text="Button 9" />
                      <TextField alignment="TOP_CENTER" layoutX="341.0" layoutY="26.0" prefHeight="25.0" prefWidth="28.0" text="10" />
                </AnchorPane>
             </children>
    </AnchorPane>
    


    启用时 主窗口。fxml ,单击菜单后 File > Analysis > New ,应该放在 主持人。fxml 内容到 主窗口。fxml 居中但是,我得到以下堆栈跟踪错误:

     Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
            at projecterror.controller.MainWindow.lambda$0(MainWindow.java:35)
            at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
            at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
            at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
            at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
            at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
            at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
            at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
            at javafx.event.Event.fireEvent(Event.java:198)
            at javafx.scene.control.MenuItem.fire(MenuItem.java:462)
            at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1405)
            at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$343(ContextMenuContent.java:1358)
            at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
            at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
            at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
            at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
            at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
            at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
            at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
            at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
            at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
            at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
            at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
            at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
            at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
            at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
            at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
            at javafx.event.Event.fireEvent(Event.java:198)
            at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
            at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
            at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
            at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
            at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:380)
            at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294)
            at java.security.AccessController.doPrivileged(Native Method)
            at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416)
            at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
            at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415)
            at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
            at com.sun.glass.ui.View.notifyMouse(View.java:937)
            at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
            at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
            at java.lang.Thread.run(Thread.java:745)
    

    标记NPE的行是:

    mainWindow.setCenter(anchorTest);
    

    我读过其他类似的问题,但大多数问题都与fxml文件的路径有关。我坚信这不是问题,因为在我的实际项目中,我使用相同的 类型 其他视图的路径,我到目前为止没有问题。

    我已经上传了这个项目 here 以防有人想运行该程序。

    项目结构如下:

    Project structure

    提前感谢您的帮助,我们将不胜感激!

    1 回复  |  直到 8 年前
        1
  •  2
  •   James_D    8 年前

    启动JavaFX应用程序时,将创建应用程序类的一个实例,并且(在其他情况下) start() 方法调用 Application FX应用程序线程上的实例。

    加载FXML文件时,如果FXML文件指定了控制器类,则会创建该控制器类的实例 @FXML -注释字段被注入到该实例中 initialize() 方法被调用。所有这些都发生在调用 FXMLLoader.load() .

    因此,在代码中,您最终会得到 MainWindow . 这个 开始() 方法在一个实例上调用,该实例初始化 mainWindow 字段,以及 初始化() 方法在另一个实例上调用。自从 主窗口 在第二个实例中从未初始化,当您尝试在 初始化() 方法

    将控制器类与 应用 班这个 应用 类只应作为一个整体管理应用程序的生命周期(通常,它应实现启动应用程序所需的代码):

    package projecterror.controller;
    
    import java.io.IOException;
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.geometry.Rectangle2D;
    import javafx.scene.Scene;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Screen;
    import javafx.stage.Stage;
    
    public class MainWindow extends Application {
    
        @Override
        public void start(Stage primaryStage) throws Exception {
            primaryStage.setTitle("Test Project");
    
            initMainWindow(primaryStage);
    
        }
    
        public void initMainWindow(Stage primaryStage) {
            try {
                FXMLLoader loader = new FXMLLoader();
                loader.setLocation(getClass().getResource("../view/MainWindow.fxml"));
                BorderPane mainWindow = loader.load();
    
                Scene scene = new Scene(mainWindow);
                primaryStage.setScene(scene);
    
                //Fullscreen
                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.setResizable(false);
                primaryStage.show();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    package projecterror.controller;
    
    import java.io.IOException;
    
    import javafx.fxml.FXML;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.control.Menu;
    import javafx.scene.control.MenuItem;
    import javafx.scene.layout.AnchorPane;
    import javafx.scene.layout.BorderPane;
    
    public class MainWindowController {
    
        @FXML
        private BorderPane mainWindow;
    
        @FXML
        Menu menuFile, menuAnalysis;
        @FXML
        MenuItem menuNew;
    
    
        @FXML
        private void initialize() {
            menuNew.setOnAction((event) -> {
                try {
                    FXMLLoader loader = new FXMLLoader();
                    loader.setLocation(getClass().getResource("../view/AnchorTest.fxml"));
                    AnchorPane anchorTest = (AnchorPane) loader.load();
                    mainWindow.setCenter(anchorTest);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    
    
    
    }
    

    以便控制器访问 BorderPane ,您需要从FXML注入它(注意上面控制器代码中的注释)。添加 fx:id 到FXML文件中的元素:

    <BorderPane style="-fx-background-color: #DCDCDC;" fx:id="mainWindow"
        xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" 
        fx:controller="projecterror.controller.MainWindowController">