如何在Java Swing中创建右键单击上下文菜单?


110

我当前正在通过右键单击实例化一个新菜单JMenu并将其位置设置为鼠标的位置来创建右键单击上下文菜单。是否有更好的方法?

Answers:


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

当然,这些教程会有更深入的解释。

注意:如果您发现弹出菜单与用户单击的位置相距很远,请尝试对x和y坐标使用e.getXOnScreen()e.getYOnScreen()方法。


使用上面的代码后,我得到一个错误,指出“类型Figure中的方法addMouseListener(MouseListener)不适用于自变量(PopClickListener)”,问候,Vinay

1
@ user1035905您确定PopClickListener扩展了MouseAdapter吗?
jjnguy 2011年

如何使它与键盘上的上下文菜单键一起使用?
ChristofferHammarström'12

此解决方案比kleopatra更好的唯一情况是,当您需要执行一些自定义逻辑时(例如,在不同条件下使用不同的弹出菜单);仍然,您必须添加键盘侦听器才能使用上下文菜单键

2
代表什么component
罗恩

117

这个问题有点老了-答案也一样(本教程也是如此)

在Swing中用于设置popupMenu的当前api是

myComponent.setComponentPopupMenu(myPopupMenu);

这样,将自动为鼠标和键盘触发器(后者取决于LAF)显示它。另外,它支持在容器的所有子项之间重复使用相同的弹出窗口。要启用该功能:

myChild.setInheritsPopupMenu(true);

2
@ user681159一无所知-IMO不需要,只需阅读api文档即可:-)
kleopatra 2012年

2
您如何将其与a一起使用,JTable以使其在所选行或右键单击的行上弹出?还是在这种情况下,将选择旧方法?
Alex Burdusel

1
@Burfee或通过子类增强JTable:重写getPopupLocation(..)并存储位置以供以后使用,请参阅最近在所有SwingX集合组件中实现的质量检查
kleopatra 2014年

18

Java教程的“ 如何使用菜单”一文中有一个关于调出弹出菜单的小节,其中介绍了如何使用该类。JPopupMenu

本教程中的示例代码显示了如何将MouseListeners 添加到应该显示弹出菜单的组件中,并相应地显示菜单。

(您描述的方法与本教程介绍的在组件上显示弹出菜单的方法非常相似。)


8

以下代码实现了默认的上下文菜单,该菜单从Windows复制,剪切,粘贴,全选,撤消和重做功能中获知。它也适用于LinuxMac 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在所有平台上正常工作。
Frederic Leitenberger

密钥侦听器中的另一个错误:pressedEvent.getModifiersEx() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()这些错误必须同时存在Ex或不存在Ex。该Ex版本getMenuShortcutKeyMask()只是由于Java提供10+。
Frederic Leitenberger

1

我将纠正@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制作的解决方案非常好,丰富且快速,可以在您的程序中实现,因此您应该尝试一下我们的效果。


同样不要忘记,您仍然需要导入contextMenu并创建新实例。
Đumić伊万
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.