Issue
I'm trying to create a simple GUI with javafx 12. Everything works fine except when I try to add a listener to a CheckMenuItem, despite performing the action, a NullPointerException is thrown, but I don't understand why and what is throwing that exception. If someone could help it would be awsome. Here is the code I'm working with:
This is the controller class, in the fxml it isn't specified because it's set with some variables when I create the stage with something like loader.setController(myController); (it is intended). Also opt is set before by another window with some options which opens this one. So opt can actually be true or false depending on what the user has chosen before.
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());
}
});
}
The fxml file:
<?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>
The printStackTrace:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at javafx.controls/javafx.scene.control.skin.MenuButtonSkinBase.lambda$new$7(MenuButtonSkinBase.java:188)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(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$3(WinApplication.java:174)
at java.base/java.lang.Thread.run(Thread.java:835)
UPDATE: I tried removing the listener code and adding a method to be called on action instead like this:
@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);
}
}
Unfortunately nothing changes. Please note that when I click the menu the action is correctly performed (the other menu, map_menu is correctly hidden and the application continues running) but eclipse still gives me this NullPointerException. I tried researching a bit on other threads and someone said it could be a focus problem? I'm not really sure if it's applicable to menus as well though.
(PS: I didn't include more code because it's totally unrelated to this problem, in fact if I don't touch the menu everything works just fine)
UPDATE 2: I tried substituting the CheckMenuItem with a regular MenuItem but the problem persists
Solution
After some research I found this is a known bug in openjfx-12: https://bugs.openjdk.java.net/browse/JDK-8179097
Fix is scheduled for openjfx-14. Until then I decided to fix the problem by only disabling the menu instead of setting it 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);
}
}
Answered By - IfLoveWasBornToDie92