【问题标题】:Right-click context menu for Java JTree?Java JTree的右键单击上下文菜单?
【发布时间】:2010-10-05 18:51:38
【问题描述】:

我正在尝试在 Java JTree 中实现弹出菜单。我将 DefaultTreeCellRenderer (以更改节点外观)和 DefaultTreeCellEditor (以创建组件以将事件侦听器附加到,因为显然 DefaultTreeCellRenderer.getTreeCellRendererComponent() 返回的组件不能做到这一点?)。我真的不想“编辑”节点,只是能够在节点被右键单击时弹出一个菜单,但这是我现在能想到的唯一方法......

下面是我到目前为止的代码——我只是想弄清楚如何捕获 MouseEvents。它有点工作,但很糟糕。有什么更好的方法来完成我在这里尝试做的事情?

private class My_TreeCellRenderer extends DefaultTreeCellRenderer { 
    My_TreeCellRenderer() {
        super ();
    }   

    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
        super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);

        // set label text and tool tips
        setText(((My_Object)value).getTreeLabel());
        setToolTipText(((My_Object)value).getTreeToolTip());

        return this;
    }
}

private class My_TreeCellEditor extends DefaultTreeCellEditor { 
    private MouseAdapter ma;

    My_TreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer) {
        super (tree, renderer);
        ma = new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    System.out.println("My Popup");
                }
            }
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    System.out.println("My Popup");
                }
            }
        };
    }

    public Component getTreeCellEditorComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) {
        String src_filename = null;

        // return non-editing component
        Component c = renderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, true);

        // add mouse listener if it's not listening already
        MouseListener mouseListeners[] = c.getMouseListeners();
        int i;
        for (i=0; i < mouseListeners.length && mouseListeners[i] != ma; i++);
        if (i >= mouseListeners.length)
            c.addMouseListener(ma);

        return c;
    }

    protected boolean canEditImmediately(EventObject event) {
        if (event instanceof MouseEvent && ((MouseEvent)event).getClickCount() == 1)
            return true;
        else
            return false;
    }
}

【问题讨论】:

    标签: java contextmenu jtree


    【解决方案1】:

    调用addRightClickListener() 将右键单击上下文菜单侦听器添加到您的JTree。这两个覆盖都是为了正确的跨平台功能(WindowsLinux 在此处有所不同)。

    private void addRightClickListener()
    {
        MouseListener mouseListener = new MouseAdapter()
        {
            @Override
            public void mousePressed(MouseEvent mouseEvent)
            {
                handleContextMenu(mouseEvent);
            }
    
            @Override
            public void mouseReleased(MouseEvent mouseEvent)
            {
                handleContextMenu(mouseEvent);
            }
        };
    
        tree.addMouseListener(mouseListener);
    }
    
    private void handleContextMenu(MouseEvent mouseEvent)
    {
        if (mouseEvent.isPopupTrigger())
        {
            MyContextMenu contextMenu = new MyContextMenu();
    
            contextMenu.show(mouseEvent.getComponent(),
                    mouseEvent.getX(),
                    mouseEvent.getY());
        }
    }
    

    【讨论】:

      【解决方案2】:

      这项任务很容易完成,您只需要以下内容:

      //create a class which implements the MouseListener interface and
      //implement the following in your overridden mouseClicked method
      
      @Override
      public void mouseClicked(MouseEvent e) {
      
          if (SwingUtilities.isRightMouseButton(e)) {
      
              int row = tree.getClosestRowForLocation(e.getX(), e.getY());
              tree.setSelectionRow(row);
              popupMenu.show(e.getComponent(), e.getX(), e.getY());
          }
      }
      

      然后您可以将此自定义侦听器添加到所需的树中。

      【讨论】:

        【解决方案3】:

        直接出JTree API

         // If you are interested in detecting either double-click events or when a user clicks on a node, regardless of whether or not it was selected, we recommend you do the following:
        
         final JTree tree = ...;
        
         MouseListener ml = new MouseAdapter() {
             public void mousePressed(MouseEvent e) {
                 int selRow = tree.getRowForLocation(e.getX(), e.getY());
                 TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
                 if(selRow != -1) {
                     if(e.getClickCount() == 1) {
                         mySingleClick(selRow, selPath);
                     }
                     else if(e.getClickCount() == 2) {
                         myDoubleClick(selRow, selPath);
                     }
                 }
             }
         };
         tree.addMouseListener(ml);
        

        当然你需要修改一下右键而不是左键

        【讨论】:

          【解决方案4】:

          谢谢大家。当我花费这么多精力来实现一个简单的弹出窗口时,我就知道出了点问题。

          起初我忽略了这种想法,因为使用 x 和 y 坐标来查找我正在寻找的节点感觉很奇怪,但我想这就是这样做的方法。

              // add MouseListener to tree
              MouseAdapter ma = new MouseAdapter() {
                  private void myPopupEvent(MouseEvent e) {
                      int x = e.getX();
                      int y = e.getY();
                      JTree tree = (JTree)e.getSource();
                      TreePath path = tree.getPathForLocation(x, y);
                      if (path == null)
                          return; 
          
                      tree.setSelectionPath(path);
          
                      My_Obj obj = (My_Obj)path.getLastPathComponent();
          
                      String label = "popup: " + obj.getTreeLabel();
                      JPopupMenu popup = new JPopupMenu();
                      popup.add(new JMenuItem(label));
                      popup.show(tree, x, y);
                  }
                  public void mousePressed(MouseEvent e) {
                      if (e.isPopupTrigger()) myPopupEvent(e);
                  }
                  public void mouseReleased(MouseEvent e) {
                      if (e.isPopupTrigger()) myPopupEvent(e);
                  }
              };
          
              (...)
          
              JTree tree = new JTree();
              tree.addMouseListener(ma);
          

          【讨论】:

          • 您每次都在创建一个 JPopupMenu。将创建移动到其他地方,只有在事件上对其进行修改后才能完成
          • 这是过早优化的一个很好的例子 (en.wikiquote.org/wiki/Donald_Knuth)。除非有理由(例如,缓慢的资源初始化),否则创建长寿命对象是没有意义的。
          【解决方案5】:

          我认为你让事情变得比他们需要的更难。
          JTree 上有几个“add_foo_Listener”方法。实现其中之一(TreeSelectionListener 看起来差不多),然后你就得到了当前选定的节点。
          实现一个 MouseListener 以便您可以检测到右键单击事件(并将其添加到 JTree,因为 JTree 是一个组件),然后您应该拥有发布上下文相关菜单所需的一切。
          查看此tutorial 了解更多详情。

          【讨论】:

            【解决方案6】:

            渲染器只是一个短暂的“橡皮图章”,因此在其上添加输入侦听器不会特别有用。正如您所指出的,编辑器只有在您做出编辑手势时才会出现。所以你想为 JTree 添加一个监听器(假设它没有作为复合组件实现)。

            【讨论】:

              猜你喜欢
              • 2016-02-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-12-15
              • 2017-04-22
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多