Reputation: 554
In JavaFX when I use a TreeView, whenever I click on the main menus (which have submenus) sometimes they "stuck" and don't show me their submenus.
In 10 clicks seven is okay, 3 is not. I observed, that the problem shows up only, if I click to another main menu that I am in. For example:
>File
New File
Open File
Close
>Tools
Settings
So if I click: File, it shows me it's submenus (New, Open, Close). If I click it again, it closes the submenus. BUT!
When I click to another submenu, just like "Settings" and after I click to File (to expand, or collapse it's submenus) I get this error message:
java.lang.NullPointerException
at utiokos_program.FoablakController$1.changed(FoablakController.java:166)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:196)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
at javafx.beans.property.ReadOnlyObjectWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyObjectWrapper.java:195)
at javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:161)
at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:130)
at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:163)
at javafx.scene.control.SelectionModel.setSelectedItem(SelectionModel.java:101)
at javafx.scene.control.MultipleSelectionModelBase$1.invalidated(MultipleSelectionModelBase.java:65)
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:155)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:195)
at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:161)
at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:130)
at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:163)
at javafx.scene.control.SelectionModel.setSelectedIndex(SelectionModel.java:67)
at javafx.scene.control.MultipleSelectionModelBase.shiftSelection(MultipleSelectionModelBase.java:253)
at javafx.scene.control.TreeView$TreeViewBitSetSelectionModel$2.handle(TreeView.java:1114)
at javafx.scene.control.TreeView$TreeViewBitSetSelectionModel$2.handle(TreeView.java:1059)
at com.sun.javafx.scene.control.WeakEventHandler.handle(WeakEventHandler.java:62)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:64)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:28)
at javafx.event.Event.fireEvent(Event.java:171)
at javafx.scene.control.TreeItem.fireEvent(TreeItem.java:713)
at javafx.scene.control.TreeItem.access$300(TreeItem.java:197)
at javafx.scene.control.TreeItem$5.invalidated(TreeItem.java:529)
at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:127)
at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:161)
at javafx.beans.property.BooleanProperty.setValue(BooleanProperty.java:81)
at javafx.scene.control.TreeItem.setExpanded(TreeItem.java:509)
at com.sun.javafx.scene.control.behavior.TreeCellBehavior.doSelect(TreeCellBehavior.java:192)
at com.sun.javafx.scene.control.behavior.TreeCellBehavior.mousePressed(TreeCellBehavior.java:122)
at com.sun.javafx.scene.control.skin.SkinBase$4.handle(SkinBase.java:335)
at com.sun.javafx.scene.control.skin.SkinBase$4.handle(SkinBase.java:329)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:64)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:38)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:33)
at javafx.event.Event.fireEvent(Event.java:171)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3369)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3209)
at javafx.scene.Scene$MouseHandler.access$1900(Scene.java:3164)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1582)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2267)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:250)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:173)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:292)
at com.sun.glass.ui.View.handleMouseEvent(View.java:530)
at com.sun.glass.ui.View.notifyMouse(View.java:924)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:17)
at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:67)
at java.lang.Thread.run(Thread.java:744)
After I click it again, and it is okay, it shows me it's subs again! (Since now the File was the last I clicked and not the Settings)
//One possible solution would be to disable the treeview's collapse, and then I use it everytime in expanded mode. Is it possible to disable collapsing in JavaFX Treeview?
//I copy the whole FoablakController.java on request
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.application.Platform;
import javafx.scene.layout.StackPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.Node;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.Event;
import javafx.event.EventDispatchChain;
import javafx.event.EventDispatcher;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
public class FoablakController implements Initializable {
public Windows operation = null;
private final Node fileicon = new ImageView(new Image(getClass().getResourceAsStream("file.png")));
private final Node editicon = new ImageView(new Image(getClass().getResourceAsStream("edit.png")));
private final Node windowsicon = new ImageView(new Image(getClass().getResourceAsStream("windows.png")));
private final Node toolsicon = new ImageView(new Image(getClass().getResourceAsStream("tools.png")));
private final Node helpicon = new ImageView(new Image(getClass().getResourceAsStream("help.png")));
@FXML
public static StackPane menuholder;
@FXML
public static StackPane main_right;
@FXML
public static StackPane help_right;
@FXML
public static StackPane contact_right;
@FXML
public static StackPane settings_right;
@FXML
public static StackPane contrast_right;
@FXML
public static StackPane comments_right;
@FXML
public static StackPane nice_right;
@FXML
public static StackPane faq_right;
@FXML
public TextArea summary;
@FXML
public static TextArea textArea_help_summary;
@FXML
public Button btn_print;
@FXML
public void Quitgomb (ActionEvent event) {
Platform.exit();
}
public void ClearScreen(){
main_right.setVisible(false);
help_right.setVisible(false);
settings_right.setVisible(false);
contrast_right.setVisible(false);
contact_right.setVisible(false);
comments_right.setVisible(false);
nice_right.setVisible(false);
faq_right.setVisible(false);
}
@Override
public void initialize(URL url, ResourceBundle rb) {
TreeItem<String> treeItemRoot1 = new TreeItem<> ("Menu");
TreeItem<String> nodeItemA = new TreeItem<>("File",fileicon);
TreeItem<String> nodeItemB = new TreeItem<>("Edit",editicon);
TreeItem<String> nodeItemC = new TreeItem<>("Windows",windowsicon);
TreeItem<String> nodeItemD = new TreeItem<>("Tools",toolsicon);
TreeItem<String> nodeItemE = new TreeItem<>("Help",helpicon);
treeItemRoot1.getChildren().addAll(nodeItemA, nodeItemB, nodeItemC,nodeItemD,nodeItemE);
nodeItemA.setExpanded(true);
nodeItemB.setExpanded(true);
nodeItemC.setExpanded(true);
nodeItemD.setExpanded(true);
nodeItemE.setExpanded(true);
TreeItem<String> nodeItemA1 = new TreeItem<>("New File");
TreeItem<String> nodeItemA2 = new TreeItem<>("Open");
TreeItem<String> nodeItemA3 = new TreeItem<>("Quit");
nodeItemA.getChildren().addAll(nodeItemA1, nodeItemA2, nodeItemA3);
TreeItem<String> nodeItemB1 = new TreeItem<>("Edit A");
TreeItem<String> nodeItemB2 = new TreeItem<>("Edit B");
TreeItem<String> nodeItemB3 = new TreeItem<>("Edit C");
TreeItem<String> nodeItemB4 = new TreeItem<>("Edit D");
TreeItem<String> nodeItemB5 = new TreeItem<>("Edit E");
TreeItem<String> nodeItemB6 = new TreeItem<>("Edit F");
nodeItemB.getChildren().addAll(nodeItemB1, nodeItemB2, nodeItemB3, nodeItemB4, nodeItemB5, nodeItemB6);
TreeItem<String> nodeItemC1 = new TreeItem<>("Windows Settings");
TreeItem<String> nodeItemC2 = new TreeItem<>("Windows Brightness");
TreeItem<String> nodeItemC3 = new TreeItem<>("Windows Quit");
nodeItemC.getChildren().addAll(nodeItemC1, nodeItemC2, nodeItemC3);
TreeItem<String> nodeItemD1 = new TreeItem<>("Settings");
TreeItem<String> nodeItemD2 = new TreeItem<>("Print");
nodeItemD.getChildren().addAll(nodeItemD1, nodeItemD2);
TreeItem<String> nodeItemE1 = new TreeItem<>("Help");
TreeItem<String> nodeItemE2 = new TreeItem<>("FAQ");
nodeItemE.getChildren().addAll(nodeItemE1, nodeItemE2);
TreeView<String> treeView = new TreeView<>(treeItemRoot1);
treeView.setShowRoot(false);
menuholder.getChildren().add(treeView);
//
treeView.getSelectionModel().selectedItemProperty().addListener( new ChangeListener() {
public void changed(ObservableValue observable, Object oldValue,
Object newValue) {
operation = new Windows();
TreeItem<String> selectedItem = (TreeItem<String>) newValue;
String actualmenu;
**actualmenu = selectedItem.getValue();**
if (null != actualmenu) {
switch (actualmenu) {
case "File":
try{
selectedItem.setExpanded(true);
}
catch (Exception ex) {
Logger.getLogger(FoablakController.class.getName()).log(Level.SEVERE, null, ex);
}
break;
case "Edit":
selectedItem.setExpanded(true);
break;
case "Windows":
selectedItem.setExpanded(true);
break;
case "Tools":
selectedItem.setExpanded(true);
break;
case "Help":
selectedItem.setExpanded(true);
break;
case "New File":
try {
menuholder.setDisable(true);
textArea_help_summary.setDisable(true);
operation.first();
} catch (Exception ex) {
Logger.getLogger(FoablakController.class.getName()).log(Level.SEVERE, null, ex);
}
break;
case "Open":
System.out.println("OK");
break;
case "Quit":
System.out.println("OK");
break;
case "Edit A":
System.out.println("OK");
break;
case "Edit B":
ClearScreen();
contrast_right.setVisible(true);
case "Edit C":
break;
case "Edit D":
System.out.println("OK");
break;
case "Edit E":
System.out.println("OK");
break;
}
}
}
});
}
}
Upvotes: 2
Views: 2392
Reputation: 10859
Sir;
Solution 1
This is what i think is happening, ChangeListener
listens to change events, whey you click an item in the TreeView
it is triggered, when you click a sub-item in it, it is also triggered, with that when you try to collapse an item, it is triggered twice, but one for the collapsing which does not return any value(hence your newValue is null so when you try to assign an object to null, it is null, therefore calling a function on a null object results in NPE) and the second for the TreeItem
selection, which returns the child TreeItem
as a value. so quick fix my change listener is a little different from yours in terms of the type parameters,but its no biggie
ChangeListener<TreeItem<String>>() {
public void changed(ObservableValue<? extends TreeItem<String>> observable,TreeItem<String> oldValue, TreeItem<String> newValue) {
TreeItem<String> selectedItem;
if(newValue != null){
selectedItem = newValue;
}else{
selectedItem = oldValue; // here it s null so i am assigning it
// to the old value
}
// add the other codes
Solution 2
Actually this solutin 2 goes to your question "One possible solution would be to disable the treeview's collapse, and then I use it everytime in expanded mode. Is it possible to disable collapsing in JavaFX Treeview?" the answer is YES.. here
yourTreeItem.addEventHandler(TreeItem.branchCollapsedEvent(),
new EventHandler<TreeModificationEvent<String>>() {
@Override
public void handle(TreeModificationEvent<String> event) {
event.getTreeItem().setExpanded(true);
}
});
hope it helps
Upvotes: 3