Как создать контекстное меню правой кнопки мыши в Java Swing?

В настоящее время я создаю контекстное меню, вызываемое щелчком правой кнопкой мыши, создавая экземпляр нового JMenu при щелчке правой кнопкой мыши и устанавливая его местоположение в соответствии с положением мыши ... Есть ли лучший способ?


person Wayne    schedule 20.04.2009    source источник


Ответы (5)


Вероятно, вы вручную вызываете setVisible(true) в меню. Это может вызвать неприятные ошибки в меню.

Метод show(Component, int x, int x) обрабатывает все, что вам нужно, (выделение элементов при наведении курсора и закрытие всплывающего окна при необходимости), где использование setVisible(true) просто показывает меню без добавления какого-либо дополнительного поведения.

Чтобы создать всплывающее меню при щелчке правой кнопкой мыши, просто создайте _4 _ .

class PopUpDemo extends JPopupMenu {
    JMenuItem anItem;
    public PopUpDemo() {
        anItem = new JMenuItem("Click Me!");
        add(anItem);
    }
}

Затем все, что вам нужно сделать, это добавить пользовательский MouseListener к компонентам, для которых должно отображаться всплывающее меню.

class PopClickListener extends MouseAdapter {
    public void mousePressed(MouseEvent e) {
        if (e.isPopupTrigger())
            doPop(e);
    }

    public void mouseReleased(MouseEvent e) {
        if (e.isPopupTrigger())
            doPop(e);
    }

    private void doPop(MouseEvent e) {
        PopUpDemo menu = new PopUpDemo();
        menu.show(e.getComponent(), e.getX(), e.getY());
    }
}

// Then on your component(s)
component.addMouseListener(new PopClickListener());

Конечно, в руководствах есть немного более подробное описание объяснение.

Примечание. Если вы заметили, что всплывающее меню появляется далеко от того места, где щелкнул пользователь, попробуйте использовать методы e.getXOnScreen() и e.getYOnScreen() для координат x и y.

person jjnguy    schedule 20.04.2009
comment
После использования приведенного выше кода я получаю сообщение об ошибке, в котором говорится, что метод addMouseListener (MouseListener) в типе Figure неприменим для аргументов (PopClickListener) С уважением, Винай - person ; 08.11.2011
comment
@ user1035905 Вы убедились, что PopClickListener расширяет MouseAdapter? - person jjnguy; 08.11.2011
comment
Как заставить его работать с клавишей контекстного меню на клавиатуре? - person Christoffer Hammarström; 23.12.2012
comment
единственный случай, когда это решение лучше, чем у клеопатры, - это когда вам нужна некоторая настраиваемая логика (например, разные всплывающие меню в разных условиях); тем не менее, вам нужно добавить слушателя клавиатуры для работы с клавишей контекстного меню - person ; 23.04.2013
comment
@PavelRyzhov не в классе JPopupMenu. docs.oracle. com / javase / 7 / docs / api / javax / swing /, int, int) - person jjnguy; 18.06.2013
comment
что означает component? - person Loint; 30.05.2016

Этот вопрос немного устарел - как и ответы (и само руководство)

Текущий api для настройки popupMenu в Swing:

myComponent.setComponentPopupMenu(myPopupMenu);

Таким образом, это будет отображаться автоматически, как для триггеров мыши, так и для клавиатуры (последнее зависит от LAF). Кроме того, он поддерживает повторное использование одного и того же всплывающего окна для дочерних элементов контейнера. Чтобы включить эту функцию:

myChild.setInheritsPopupMenu(true);
person kleopatra    schedule 08.11.2011
comment
@ user681159 ничего не знаю - и это не нужно, IMO, просто прочтите api doc :-) - person kleopatra; 22.01.2012
comment
Как бы вы использовали это с JTable, чтобы он появлялся в выбранной строке или в строке, где вы щелкаете правой кнопкой мыши? Или в этом случае следует выбрать старый метод? - person Alex Burdusel; 29.12.2013
comment
@Burfee либо это, либо улучшите JTable с помощью подкласса: переопределите getPopupLocation (..) и сохраните местоположение для последующего использования, см. Недавний QA, который реализован во всех компонентах коллекции SwingX - person kleopatra; 08.01.2014
comment
@RanjitVamadevan, в чем вы видите необходимость форматирования? - person kleopatra; 23.11.2020

Есть раздел Открытие всплывающего меню в статье Как использовать меню в Учебники по Java, в которых объясняется, как использовать _ 1_ класс.

В примере кода в руководстве показано, как добавить MouseListeners к компонентам, которые должны отображать всплывающее меню и соответственно отображать меню.

(Метод, который вы описываете, довольно похож на способ, которым в учебнике представлен способ отображения всплывающего меню на компоненте.)

person coobird    schedule 20.04.2009

Следующий код реализует контекстное меню по умолчанию, известное из Windows, с функциями копирования, вырезания, вставки, выбора всего, отмены и повтора. Он также работает с Linux и Mac OS X:

import javax.swing.*;
import javax.swing.text.JTextComponent;
import javax.swing.undo.UndoManager;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class DefaultContextMenu extends JPopupMenu
{
    private Clipboard clipboard;

    private UndoManager undoManager;

    private JMenuItem undo;
    private JMenuItem redo;
    private JMenuItem cut;
    private JMenuItem copy;
    private JMenuItem paste;
    private JMenuItem delete;
    private JMenuItem selectAll;

    private JTextComponent textComponent;

    public DefaultContextMenu()
    {
        undoManager = new UndoManager();
        clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();

        addPopupMenuItems();
    }

    private void addPopupMenuItems()
    {
        undo = new JMenuItem("Undo");
        undo.setEnabled(false);
        undo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        undo.addActionListener(event -> undoManager.undo());
        add(undo);

        redo = new JMenuItem("Redo");
        redo.setEnabled(false);
        redo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        redo.addActionListener(event -> undoManager.redo());
        add(redo);

        add(new JSeparator());

        cut = new JMenuItem("Cut");
        cut.setEnabled(false);
        cut.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        cut.addActionListener(event -> textComponent.cut());
        add(cut);

        copy = new JMenuItem("Copy");
        copy.setEnabled(false);
        copy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        copy.addActionListener(event -> textComponent.copy());
        add(copy);

        paste = new JMenuItem("Paste");
        paste.setEnabled(false);
        paste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        paste.addActionListener(event -> textComponent.paste());
        add(paste);

        delete = new JMenuItem("Delete");
        delete.setEnabled(false);
        delete.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        delete.addActionListener(event -> textComponent.replaceSelection(""));
        add(delete);

        add(new JSeparator());

        selectAll = new JMenuItem("Select All");
        selectAll.setEnabled(false);
        selectAll.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        selectAll.addActionListener(event -> textComponent.selectAll());
        add(selectAll);
    }

    private void addTo(JTextComponent textComponent)
    {
        textComponent.addKeyListener(new KeyAdapter()
        {
            @Override
            public void keyPressed(KeyEvent pressedEvent)
            {
                if ((pressedEvent.getKeyCode() == KeyEvent.VK_Z)
                        && ((pressedEvent.getModifiersEx() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) != 0))
                {
                    if (undoManager.canUndo())
                    {
                        undoManager.undo();
                    }
                }

                if ((pressedEvent.getKeyCode() == KeyEvent.VK_Y)
                        && ((pressedEvent.getModifiersEx() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) != 0))
                {
                    if (undoManager.canRedo())
                    {
                        undoManager.redo();
                    }
                }
            }
        });

        textComponent.addMouseListener(new MouseAdapter()
        {
            @Override
            public void mousePressed(MouseEvent releasedEvent)
            {
                handleContextMenu(releasedEvent);
            }

            @Override
            public void mouseReleased(MouseEvent releasedEvent)
            {
                handleContextMenu(releasedEvent);
            }
        });

        textComponent.getDocument().addUndoableEditListener(event -> undoManager.addEdit(event.getEdit()));
    }

    private void handleContextMenu(MouseEvent releasedEvent)
    {
        if (releasedEvent.getButton() == MouseEvent.BUTTON3)
        {
            processClick(releasedEvent);
        }
    }

    private void processClick(MouseEvent event)
    {
        textComponent = (JTextComponent) event.getSource();
        textComponent.requestFocus();

        boolean enableUndo = undoManager.canUndo();
        boolean enableRedo = undoManager.canRedo();
        boolean enableCut = false;
        boolean enableCopy = false;
        boolean enablePaste = false;
        boolean enableDelete = false;
        boolean enableSelectAll = false;

        String selectedText = textComponent.getSelectedText();
        String text = textComponent.getText();

        if (text != null)
        {
            if (text.length() > 0)
            {
                enableSelectAll = true;
            }
        }

        if (selectedText != null)
        {
            if (selectedText.length() > 0)
            {
                enableCut = true;
                enableCopy = true;
                enableDelete = true;
            }
        }

        if (clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor) && textComponent.isEnabled())
        {
            enablePaste = true;
        }

        undo.setEnabled(enableUndo);
        redo.setEnabled(enableRedo);
        cut.setEnabled(enableCut);
        copy.setEnabled(enableCopy);
        paste.setEnabled(enablePaste);
        delete.setEnabled(enableDelete);
        selectAll.setEnabled(enableSelectAll);

        // Shows the popup menu
        show(textComponent, event.getX(), event.getY());
    }

    public static void addDefaultContextMenu(JTextComponent component)
    {
        DefaultContextMenu defaultContextMenu = new DefaultContextMenu();
        defaultContextMenu.addTo(component);
    }
}

Использование:

JTextArea textArea = new JTextArea();
DefaultContextMenu.addDefaultContextMenu(textArea);

Теперь textArea будет иметь контекстное меню при щелчке правой кнопкой мыши.

person BullyWiiPlaza    schedule 02.02.2015
comment
Отличное решение. Одно: вы можете / должны использовать releasedEvent.isPopupTrigger() вместо releasedEvent.getButton() == MouseEvent.BUTTON3 для правильной работы на всех платформах. - person Frederic Leitenberger; 22.07.2020
comment
Еще одна ошибка в прослушивателе ключей: pressedEvent.getModifiersEx() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() они должны быть либо Ex, либо не Ex. Ex версия getMenuShortcutKeyMask() доступна только с версии java 10+. - person Frederic Leitenberger; 22.07.2020

Я исправлю использование этого метода, предложенного @BullyWillPlaza. Причина в том, что когда я пытаюсь добавить textArea только в contextMenu, оно не отображается, и если я добавляю его как в contextMenu, так и в какую-то панель, он обнаруживает: Другая родительская двойная ассоциация, если я пытаюсь переключиться в редактор дизайна.

TexetObjcet.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            if (SwingUtilities.isRightMouseButton(e)){
                contextmenu.add(TexetObjcet);
                contextmenu.show(TexetObjcet, 0, 0);
            }
        }
    }); 

Сделайте такой слушатель мыши для текстового объекта, на котором вам нужно всплывающее окно. Что это будет делать, так это когда вы щелкнете правой кнопкой мыши по текстовому объекту, он добавит это всплывающее окно и отобразит его. Таким образом, вы не столкнетесь с этой ошибкой. Решение, созданное @BullyWillPlaza, очень хорошее, богатое и быстрое для реализации в вашей программе, поэтому вы должны попробовать его, чтобы увидеть, как оно вам нравится.

person Đumić Branislav    schedule 25.07.2017
comment
Также не забывайте, что вам все еще нужно импортировать это contextMenu и создать новый экземпляр. - person Đumić Branislav; 25.07.2017