web-dev-qa-db-fra.com

Menu contextuel par clic droit pour Java JTree?

J'essaie d'implémenter des menus contextuels dans Java JTree. J'ai sous-classé DefaultTreeCellRenderer (pour changer l'apparence du nœud) et DefaultTreeCellEditor (pour créer des composants auxquels attacher des écouteurs d'événements, car apparemment, les composants que DefaultTreeCellRenderer.getTreeCellRendererComponent () renvoie ne le peuvent pas?). Je ne veux pas vraiment "éditer" les nœuds, je peux juste faire apparaître un menu lorsqu'un nœud est cliqué avec le bouton droit de la souris, mais c'est la seule façon dont je peux penser à le faire maintenant ...

Ci-dessous, le code que j'ai jusqu'à présent - j'essaie simplement de comprendre comment capturer MouseEvents. Cela fonctionne en quelque sorte, mais mal. Quelle est la meilleure façon d'accomplir ce que j'essaie de faire ici?

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

Cette tâche est simple à accomplir, voici tout ce dont vous avez besoin:

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

Vous pouvez ensuite ajouter cet écouteur personnalisé à l’arbre ou aux arbres de votre choix.

28
b1nary.atr0phy

Sorti tout droit de/ API JTree

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

Bien sûr, vous devez le modifier un peu pour un clic droit au lieu d'un clic gauche.

20
kazanaki

Merci tout le monde. Je savais que quelque chose n'allait pas quand je consacrais autant d'efforts à la mise en place d'un simple popup.

Au début, j'ai écarté cette ligne de pensée parce qu'il était étrange de recourir aux coordonnées x et y pour trouver le nœud que je cherchais, mais je suppose que c'est la façon de le faire.

    // 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);
12
arcanex

Je pense que vous rendez les choses bien plus difficiles que nécessaire.
JTree a plusieurs méthodes "add_foo_Listener". Implémentez l'une de celles-ci (TreeSelectionListener semble à peu près correct), puis vous obtenez le nœud actuellement sélectionné. 
Implémentez MouseListener pour pouvoir détecter l'événement de clic droit (et l'ajouter à JTree, car JTree est un composant), et vous devriez disposer de tout le nécessaire pour publier un menu contextuel.
Consultez ce tutorial pour plus de détails.

2
dw.mackie

Le moteur de rendu est seulement un "tampon encreur" transitoire, donc l'ajout d'un écouteur d'entrée à ce sujet ne sera pas particulièrement utile Comme vous le soulignez, l’éditeur n’est présent qu’une fois que vous avez proposé d’éditer. Vous souhaitez donc ajouter un écouteur à JTree (en supposant qu'il ne soit pas implémenté en tant que composant composite).

1

Appelez addRightClickListener() pour ajouter l'écouteur du menu contextuel du clic droit à votre JTree. Les deux substitutions concernent les fonctionnalités multi-plateformes appropriées (Windows et Linux diffèrent ici).

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