2009-02-05 4 views
27

Я пытаюсь реализовать всплывающие меню в Java JTree. Я подклассифицировал DefaultTreeCellRenderer (для изменения внешнего вида узла) и DefaultTreeCellEditor (для создания компонентов для присоединения прослушивателей событий, поскольку, по-видимому, Компоненты, возвращаемые DefaultTreeCellRenderer.getTreeCellRendererComponent(), не могут это сделать?). Я действительно не хочу «редактировать» узлы, просто смогу всплывать меню, когда узел получает щелчок правой кнопкой мыши, но это единственный способ, которым я могу сейчас это сделать ...Щелкните правой кнопкой мыши контекстное меню для Java JTree?

Ниже приведен код, который у меня есть до сих пор. Я просто пытаюсь понять, как захватить 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; 
    } 
} 

ответ

1

Рендеринг - это временная «резиновая штамп», поэтому добавление слушателя ввода на этом не будет особенно полезным. Редактор, как вы указываете, доступен только после того, как вы указали на редактирование. Поэтому вы хотите добавить слушателя в JTree (предполагая, что он не реализован как составной компонент).

20

Взятые прямо из 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); 

Конечно вам нужно изменить это немного для правой кнопки мыши вместо левой кнопки мыши

2

Я думаю, что вы делаете вещи способа сложнее, чем они должны быть.
У JTree есть несколько методов "add_foo_Listener". Внедрите один из них (TreeSelectionListener выглядит правильно), а затем у вас есть выбранный в данный момент узел.
Внедрите MouseListener, чтобы вы могли обнаружить событие щелчка правой кнопкой мыши (и добавить его в JTree, поскольку JTree является компонентом), а затем у вас должно быть все, что вам нужно, чтобы публиковать контекстно-зависимое меню.
Проверьте это tutorial для получения более подробной информации.

12

Спасибо всем. Я знал, что что-то не так, когда я тратил столько усилий на реализацию простого всплывающего окна.

Я отклонил эту мысль сначала, потому что было странно прибегать к координатам 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); 
+2

Вы создаете JPopupMenu каждый раз. Переместите создание в другое место, где это делается только после его изменения в событии –

+1

Это хороший пример преждевременной оптимизации (http://en.wikiquote.org/wiki/Donald_Knuth). Нет смысла создавать долгоживущий объект, пока не будет причин для этого (медленная инициализация ресурсов, например). –

25

Эта задача проста, чтобы выполнить следующее все, что вам нужно:

//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()); 
    } 
} 

Вы можете добавить этот обычай слушателя к нужному дереву (ов).

+2

+1 для адресации аспекта правой кнопки мыши вопроса OP – amaidment

0

Позвоните addRightClickListener(), чтобы добавить прослушиватель контекстного меню правой кнопкой мыши к вашему JTree. Оба переопределения предназначены для правильной межплатформенной функциональности (здесь есть Windows и Linux).

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()); 
    } 
} 
Смежные вопросы