Mr.Fireman
Mr.Fireman

Reputation: 554

JavaFX disable TreeView collapsing

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

Answers (1)

Elltz
Elltz

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

Related Questions