Як створити контекстне меню правою кнопкою миші в Java Swing?


110

Наразі я створюю контекстне меню правою кнопкою миші, використовуючи нове JMenuправоручне клацання правою кнопкою миші та встановлюючи його розташування відповідно до положення миші ... Чи є кращий спосіб?

Відповіді:


140

Ви, ймовірно, вручну дзвоните setVisible(true)в меню. Це може спричинити неприємну поведінку баггі в меню.

У show(Component, int x, int x)метод обробляє всі речі , які ви повинні відбутися, (Підкреслюючи речі при наведенні курсору і закриття спливаючого вікна при необхідності) , де використання setVisible(true)тільки показує меню без додавання будь - яких додаткових поведінки.

Щоб створити спливаюче меню правою кнопкою миші, просто створіть JPopupMenu.

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.


Після використання вищевказаного коду я отримую помилку про те, що "метод addMouseListener (MouseListener) у типі Рисунок не застосовується для аргументів (PopClickListener)" З повагою, Vinay

1
@ User1035905 ви переконаєтеся , що PopClickListenerтриває MouseAdapter?
jjnguy

Як змусити його працювати з клавішею контекстного меню на клавіатурі?
Крістофер Хаммарстрем

єдиний випадок, коли це рішення краще, ніж у клеопатри, - це коли вам потрібна спеціальна логіка (наприклад, різні спливаючі меню в різних умовах); все-таки потрібно додати слухача клавіатури для роботи з клавішею контекстного меню

2
що означає component?
Loint

117

Це питання трохи старе - як і відповіді (і підручник також)

Поточна api для встановлення popupMenu в Swing є

myComponent.setComponentPopupMenu(myPopupMenu);

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

myChild.setInheritsPopupMenu(true);

2
@ user681159 нічого не знаю - і це не потрібно, IMO, просто прочитайте api doc :-)
kleopatra

2
Як би ви використовували це, JTableщоб він з’явився на вибраному рядку або на рядку, де ви клацніть правою кнопкою миші? Або в цьому сценарії обирається старий метод?
Алекс Бурдузель

1
@Burfee або що або поліпшити JTable з допомогою підкласів: перевизначення getPopupLocation (..) і зберегти місце для подальшого використання, див недавнього QA , який реалізується у всіх компонентах збору SwingX
Kleopatra

18

Там в розділі , присвяченому виховують Контекстне меню в Як використовувати Меню статті The Java Tutorials , яка пояснює , як використовувати JPopupMenuклас.

Приклад коду в підручнику показує, як додати MouseListeners до компонентів, які мають відображати спливаюче меню, та відображає меню відповідно.

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


8

Наступний код реалізує контекстне меню за замовчуванням, відоме з 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контекстному меню буде натиснути його правою кнопкою миші.


Прекрасне рішення. Одне: ви могли / повинні використовувати releasedEvent.isPopupTrigger()замість того, releasedEvent.getButton() == MouseEvent.BUTTON3щоб правильно працювати на всіх платформах.
Фредерік Лейтенбергер

Ще одна помилка у слухачеві ключів: pressedEvent.getModifiersEx() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()вони повинні бути Exабо відсутніми, або ні Ex. ExВерсія getMenuShortcutKeyMask()доступна тільки з Java 10+.
Фредерік Лейтенбергер

1

Я виправлю використання цього методу, який запропонував @BullyWillPlaza. Причина полягає в тому, що коли я намагаюся додати textArea лише в контекстМену, це не видно, і якщо я додаю його як до контексту, так і до якоїсь панелі, вона забуває: Різне подвійне об'єднання батьків, якщо я спробую перейти до редактора дизайну.

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

Зробіть такий слухач миші таким текстовим об’єктом, на який потрібно мати спливаюче вікно. Це буде робити, коли ви клацніть правою кнопкою миші на текстовому об’єкті, то він додасть це спливаюче вікно та відобразить його. Таким чином ви не стикаєтеся з цією помилкою. Рішення, яке зроблено @BullyWillPlaza, дуже добре, насичене та швидке для впровадження у вашій програмі, тож ви повинні спробувати наш погляд, як вам це подобається.


Також не забувайте, що вам все одно потрібно імпортувати цей контекстМену та створити новий екземпляр.
Джумич Бранислав
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.