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);
}
}
我正在尝试使用 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);
}
}