Selecting/deselecting 检查菜单按钮在 javafx 中给出空指针异常

Selecting/deselecting check menu button gives null pointer exception in javafx

我正在尝试使用 javafx 12 创建一个简单的 GUI。一切正常,除了当我尝试向 CheckMenuItem 添加侦听器时,尽管执行了该操作,但抛出了 NullPointerException,但我不明白为什么什么是抛出异常。如果有人可以提供帮助,那就太棒了。这是我正在使用的代码:

这是控制器 class,在 fxml 中未指定它,因为当我使用 loader.setController(myController) 之类的东西创建舞台时,它设置了一些变量; (它的目的是)。 opt 也由另一个 window 设置,其中包含一些打开此选项的选项。所以 opt 实际上可以是真也可以是假,这取决于用户之前的选择。

private boolean opt;
@FXML Menu map_menu;
@FXML CheckMenuItem menuOpt;
public void initialize(URL arg0, ResourceBundle arg1) {
if (opt == true) {
        menuOpt.setSelected(true);
        map_menu.setVisible(true);
    } else {
        menuOpt.setSelected(false);
        map_menu.setVisible(false);
    }

    menuOpt.selectedProperty().addListener(new ChangeListener<Boolean>() {

        @Override
        public void changed(ObservableValue<? extends Boolean> ov, Boolean oldval, Boolean newval) {
            opt = newval.booleanValue();
            map_menu.setVisible(newval.booleanValue());
        }

    });

}

fxml 文件:

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

<?import javafx.scene.control.CheckMenuItem?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="900.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <MenuBar fx:id="menuBar" layoutY="2.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
        <menus>
          <Menu fx:id="menuFile" mnemonicParsing="false" text="File">
            <items>
                  <MenuItem mnemonicParsing="false" text="Change files" />
              <MenuItem mnemonicParsing="false" text="Close" />
            </items>
          </Menu>
            <Menu fx:id="menuView" mnemonicParsing="false" text="View">
              <items>
                <MenuItem fx:id="menuSwitchBasic" mnemonicParsing="false" onAction="#switch_viewToBasic" text="Switch to basic view" />
                  <MenuItem fx:id="menuSwitchDebug" mnemonicParsing="false" onAction="#switch_viewToDebug" text="Switch to debug view" />
                  <CheckMenuItem fx:id="menuOpt" mnemonicParsing="false" text="Optional features" />
              </items>
            </Menu>
            <Menu fx:id="map_menu" mnemonicParsing="false" text="Map">
              <items>
                <MenuItem mnemonicParsing="false" text="Change map" />
                  <MenuItem mnemonicParsing="false" text="Create new map" />
                  <MenuItem mnemonicParsing="false" text="Edit map" />
              </items>
            </Menu>
          <Menu fx:id="menuHelp" mnemonicParsing="false" text="Help">
            <items>
              <MenuItem mnemonicParsing="false" text="About" />
            </items>
          </Menu>
        </menus>
      </MenuBar>
      <AnchorPane fx:id="anchorPane" layoutX="6.0" layoutY="27.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="27.0" />

   </children>
</AnchorPane>

打印堆栈跟踪:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at javafx.controls/javafx.scene.control.skin.MenuButtonSkinBase.lambda$new(MenuButtonSkinBase.java:188)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop(WinApplication.java:174)
at java.base/java.lang.Thread.run(Thread.java:835)

更新:我尝试删除侦听器代码并添加一个在操作时调用的方法,而不是像这样:

@FXML void opt_menu() {
    if (menuOpt.isSelected()) {
        opt = true;
        map_menu.setDisable(false);
        map_menu.setVisible(true);  
    } else {
        opt = false;
        map_menu.setDisable(true);
        map_menu.setVisible(false);
    }
}

遗憾的是没有任何变化。请注意,当我单击菜单时,操作正确执行(另一个菜单 map_menu 被正确隐藏并且应用程序继续 运行)但是 eclipse 仍然给我这个 NullPointerException。我尝试在其他线程上进行一些研究,有人说这可能是焦点问题?不过我不确定它是否也适用于菜单。

(PS:我没有包含更多代码,因为它与这个问题完全无关,事实上,如果我不触摸菜单,一切正常)

更新 2:我尝试用常规 MenuItem 替换 CheckMenuItem,但问题仍然存在

发布的代码不是 mre 这留下了很多猜测。
目前还不清楚控制器是如何被调用的,因为fxml文件没有指定控制器。您需要使用 AnchorPane 标签内的 fx:controller=" . . .Controller " 指定它。

控制器(实现Initializable)需要包含fxml中定义的两个方法:public void switch_viewToBasic(ActionEvent e)public void switch_viewToDebug(ActionEvent e)

旁注:当调用 initialize(...) 时,opt 始终为 false,因此 if (opt == true) 不执行任何操作。

经过一些研究,我发现这是 openjfx-12 中的一个已知错误: https://bugs.openjdk.java.net/browse/JDK-8179097

计划为 openjfx-14 修复。 在那之前,我决定通过仅禁用菜单而不是设置菜单来解决问题 visible/invisible

        /*This method is subject of a known bug: https://bugs.openjdk.java.net/browse/JDK-8179097, this bug is
     * already in list to be fixed in a later version of openjfx */
//  private void refresh_opt() {
//      if (this.opt == true) {
//          map_menu.setDisable(false);
//          map_menu.setVisible(true);
//      } else {
//          map_menu.setDisable(true);
//          map_menu.setVisible(false);
//      }
//  }

    private void refresh_opt() {
        if (this.opt == true) {
            map_menu.setDisable(false);
        } else {
            map_menu.setDisable(true);
        }
    }