Щелкните правой кнопкой мыши контекстное меню для Java JTree? - PullRequest
27 голосов
/ 05 февраля 2009

Я пытаюсь реализовать всплывающие меню в 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;
    }
}

Ответы [ 6 ]

28 голосов
/ 02 июня 2012

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

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

Затем вы можете добавить этот пользовательский прослушиватель к желаемым деревьям.

20 голосов
/ 06 февраля 2009

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

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

12 голосов
/ 06 февраля 2009

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

Сначала я отклонил эту мысль, потому что было странно прибегать к координатам 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 голосов
/ 06 февраля 2009

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

1 голос
/ 05 февраля 2009

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

0 голосов
/ 30 марта 2017

Позвоните 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());
    }
}
...