JavaFX 禁用 TreeView 折叠

JavaFX disable TreeView collapsing

在 JavaFX 中,当我使用 TreeView 时,每当我单击主菜单(有子菜单)时,有时它们 "stuck" 并且不显示它们的子菜单。

10 次点击中,7 次可以,3 次则不行。我观察到,只有当我单击我所在的另一个主菜单时,问题才会出现。例如:

>File
   New File
   Open File
   Close
>Tools
   Settings

因此,如果我单击:文件,它会向我显示它的子菜单(新建、打开、关闭)。如果我再次单击它,它会关闭子菜单。 但是!

当我点击另一个子菜单时,就像 "Settings" 一样,在我点击文件(展开或折叠它的子菜单)后,我收到此错误消息:

java.lang.NullPointerException
at utiokos_program.FoablakController.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.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.handle(TreeView.java:1114)
at javafx.scene.control.TreeView$TreeViewBitSetSelectionModel.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.access0(TreeItem.java:197)
at javafx.scene.control.TreeItem.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.handle(SkinBase.java:335)
at com.sun.javafx.scene.control.skin.SkinBase.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.access00(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.access0(WinApplication.java:17)
at com.sun.glass.ui.win.WinApplication.run(WinApplication.java:67)
at java.lang.Thread.run(Thread.java:744)

我再次点击后,正常了,又显示是sub! (从现在开始我最后点击的是文件而不是设置)

//一种可能的解决方案是禁用树视图的折叠,然后我每次都在展开模式下使用它。是否可以在 JavaFX Treeview 中禁用折叠?

//我根据要求复制了整个FoablakController.java

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;
                         }
        }
                            }

      });

            }






}

先生;

解决方案 1

这就是我认为正在发生的事情,ChangeListener 监听更改事件,当你点击 TreeView 中的一个项目时它会被触发,当你点击其中的一个子项目时,它也会被触发,当你试图折叠一个项目时,它会被触发两次,但一次是为了折叠而没有 return 任何值(因此你的 newValue 是 null 所以当你试图将一个对象分配给 null ,它为空,因此在空对象上调用函数会导致 NPE),第二个用于 TreeItem 选择,return 将子 TreeItem 作为值。如此快速修复我的更改侦听器在类型参数方面与您的有所不同,但这没什么大不了的

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

解决方案 2

实际上这个解决方案 2 解决了您的问题“一个可能的解决方案是禁用 treeview 的折叠,然后我每次都在扩展模式下使用它。是否可以在 JavaFX Treeview 中禁用折叠? " 答案是肯定的..这里

yourTreeItem.addEventHandler(TreeItem.branchCollapsedEvent(), 
           new EventHandler<TreeModificationEvent<String>>() {

    @Override
    public void handle(TreeModificationEvent<String> event) {           
                event.getTreeItem().setExpanded(true);
            }
        });

希望对您有所帮助