2009-02-05 6 views
27

Sto cercando di implementare i menu a comparsa in Java JTree. Ho sottotlassato DefaultTreeCellRenderer (per cambiare l'aspetto del nodo) e DefaultTreeCellEditor (per creare componenti per allegare i listener di eventi, dal momento che apparentemente i componenti che DefaultTreeCellRenderer.getTreeCellRendererComponent() restituisce non possono farlo?). Non voglio veramente "modificare" i nodi, solo essere in grado di aprire un menu quando un nodo viene fatto clic con il pulsante destro, ma questo è l'unico modo in cui posso pensare di farlo adesso ...Fare clic con il pulsante destro del menu di scelta rapida per Java JTree?

Di seguito è riportato il codice che ho finora-- Sto solo cercando di capire come catturare MouseEvents. È una specie di lavoro, ma male. Qual è un modo migliore per realizzare ciò che sto cercando di fare qui?

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

risposta

1

Il Renderer è solo un "timbro di gomma" temporaneo, quindi aggiungere un listener di input su quello non sarà particolarmente utile. L'editor, come tu fai notare, è presente solo una volta che hai fatto il gesto di modificare. Quindi vuoi aggiungere un listener al JTree (supponendo che non sia implementato come un componente composito).

20

Preso destra, fuori dalla 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); 

Naturalmente è necessario modificare un po 'per il tasto destro del mouse, invece di clic sinistro

2

Credo che stai facendo le cose modo più difficile di quanto hanno bisogno di essere.
JTree ha diversi metodi "add_foo_Listener" su di esso. Implementare uno di questi (TreeSelectionListener sembra a destra), e quindi hai il nodo attualmente selezionato.
Implementare un MouseListener in modo da poter rilevare l'evento del clic destro (e aggiungerlo a JTree, dal momento che JTree è un componente) e quindi è necessario disporre di tutto ciò che è necessario per pubblicare un menu sensibile al contesto.
Dai un'occhiata a questo tutorial per ulteriori dettagli.

12

Grazie a tutti. Sapevo che c'era qualcosa di sbagliato quando stavo spendendo così tanto per implementare un semplice popup.

All'inizio ho respinto questa linea di pensiero perché era strano ricorrere alle coordinate x e y per trovare il nodo che sto cercando, ma immagino che questo sia il modo per farlo.

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

Si sta creando un JPopupMenu ogni volta. Sposta la creazione in un'altra posizione dove viene eseguita solo dopo averla modificata sull'evento –

+1

Questo è un buon esempio di ottimizzazione prematura (http://en.wikiquote.org/wiki/Donald_Knuth). Non ha senso creare un oggetto longevo finché non c'è una ragione per farlo (inizializzazione di risorse lente, ad esempio). –

25

Questo compito è semplice da realizzare, il seguente è tutto ciò che serve:

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

È quindi possibile aggiungere questo listener personalizzato per il vostro albero desiderata (s).

+2

+1 per indirizzare l'aspetto del tasto destro della domanda OP – amaidment

0

Chiama il numero addRightClickListener() per aggiungere il listener del menu di scelta rapida al tuo JTree. Entrambi gli override servono per una corretta funzionalità multipiattaforma (Windows e Linux differiscono qui).

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