2009-02-05 39 views
27

Estoy tratando de implementar menús emergentes en Java JTree. He subclasificado DefaultTreeCellRenderer (para cambiar la apariencia del nodo) y DefaultTreeCellEditor (para crear Componentes para adjuntar detectores de eventos, ya que aparentemente los Componentes que DefaultTreeCellRenderer.getTreeCellRendererComponent() devuelven no pueden hacerlo). Realmente no quiero "editar" los nodos, solo ser capaz de abrir un menú cuando se hace clic derecho en un nodo, pero esta es la única forma en que se me ocurre hacerlo ahora ...Haga clic derecho en el menú contextual para Java JTree?

A continuación se muestra el código que tengo hasta ahora, solo estoy tratando de averiguar cómo capturar MouseEvents. De alguna manera funciona, pero mal. ¿Cuál es una mejor manera de lograr lo que estoy tratando de hacer aquí?

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

Respuesta

1

El Renderer es solo un "sello de goma" transitorio, por lo que agregar un oyente de entrada no será particularmente útil. El Editor, como usted señala, solo está allí una vez que ha hecho un gesto para editar. Por lo tanto, desea agregar un oyente al JTree (suponiendo que no esté implementado como un componente compuesto).

20

tomada justo fuera de la 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); 

Por supuesto, tiene que modificar un poco de botón derecho del ratón en lugar de la izquierda haga clic

2

Creo que estás haciendo las cosas mucho más difícil de lo que necesitan ser.
JTree tiene varios métodos "add_foo_Listener" en él. Implementa uno de ellos (TreeSelectionListener se ve bien), y luego tienes el nodo seleccionado actualmente.
Implemente un MouseListener para que pueda detectar el evento de clic derecho (y agregarlo al JTree, ya que JTree es un Componente), y luego debe tener todo lo que necesita para publicar un menú contextual.
Echa un vistazo a este tutorial para más detalles.

12

Gracias a todos. Sabía que algo andaba mal cuando estaba gastando tanto esfuerzo en implementar una ventana emergente simple.

Al principio, descarté esta línea de pensamiento porque me resultaba extraño recurrir a las coordenadas x e y para encontrar el nodo que busco, pero supongo que esta es la manera de hacerlo.

// 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

Está creando un JPopupMenu todo el tiempo. Mueva la creación a otro lugar donde solo se haga una vez para modificarla en el evento –

+1

Este es un buen ejemplo de optimización prematura (http://en.wikiquote.org/wiki/Donald_Knuth). No tiene sentido crear un objeto de larga vida hasta que haya una razón para hacerlo (inicialización lenta de recursos, por ejemplo). –

25

Esta tarea es fácil de lograr, lo siguiente es todo lo que necesita:

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

A continuación, puede agregar esta escucha personalizado a su árbol (s) deseada.

+2

+1 para abordar el aspecto de clic derecho de la pregunta OP – amaidment

0

Llame addRightClickListener() para agregar el oyente del menú contextual al menú contextual JTree. Ambas anulaciones son para una funcionalidad adecuada multiplataforma (Windows y Linux difieren aquí).

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