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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/766956/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:14:14  来源:igfitidea点击:

How do I create a right click context menu in Java Swing?

javaswingcontextmenujpopupmenu

提问by Wayne

I'm currently creating a right-click context menu by instantiating a new JMenuon right click and setting its location to that of the mouse's position... Is there a better way?

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

采纳答案by jjnguy

You are probably manually calling setVisible(true)on the menu. That can cause some nasty buggy behavior in the menu.

您可能正在手动调用setVisible(true)菜单。这可能会导致菜单中出现一些令人讨厌的错误行为。

The show(Component, int x, int x)method handles all of the things you need to happen, (Highlighting things on mouseover and closing the popup when necessary) where using setVisible(true)just shows the menu without adding any additional behavior.

show(Component, int x, int x)方法处理您需要发生的所有事情,(在鼠标悬停时突出显示内容并在必要时关闭弹出窗口),其中使用setVisible(true)仅显示菜单而不添加任何其他行为。

To make a right click popup menu simply create a JPopupMenu.

要制作右键单击弹出菜单,只需创建一个JPopupMenu.

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

Then, all you need to do is add a custom MouseListenerto the components you would like the menu to popup for.

然后,您需要做的就是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());

Of course, the tutorials have a slightly more in-depthexplanation.

当然,教程有稍微更深入的解释。

Note:If you notice that the popup menu is appearing way off from where the user clicked, try using the e.getXOnScreen()and e.getYOnScreen()methods for the x and y coordinates.

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

回答by coobird

There's a section on Bringing Up a Popup Menuin the How to Use Menusarticle of The Java Tutorialswhich explains how to use the JPopupMenuclass.

The Java TutorialsHow to Use Menus文章中有一个关于创建弹出菜单的部分,它解释了如何使用该类。JPopupMenu

The example code in the tutorial shows how to add MouseListeners to the components which should display a pop-up menu, and displays the menu accordingly.

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

(The method you describe is fairly similar to the way the tutorial presents the way to show a pop-up menu on a component.)

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

回答by kleopatra

This question is a bit old - as are the answers (and the tutorial as well)

这个问题有点旧 - 答案也是如此(以及教程)

The current api for setting a popupMenu in Swing is

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

myComponent.setComponentPopupMenu(myPopupMenu);

This way it will be shown automagically, both for mouse and keyboard triggers (the latter depends on LAF). Plus, it supports re-using the same popup across a container's children. To enable that feature:

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

myChild.setInheritsPopupMenu(true);

回答by BullyWiiPlaza

The following code implements a default context menu known from Windowswith copy, cut, paste, select all, undo and redo functions. It also works on Linuxand Mac OS X:

以下代码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);
    }
}

Usage:

用法:

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

Now the textAreawill have a context menu when it is right-clicked on.

现在,textArea当它被右键单击时将有一个上下文菜单。

回答by ?umi? Branislav

I will correct usage for that method that @BullyWillPlaza suggested. Reason is that when I try to add add textArea to only contextMenu it's not visible, and if i add it to both to contextMenu and some panel it ecounters: Different parent double association if i try to switch to Design editor.

我将更正@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);
            }
        }
    }); 

Make mouse listener like this for text object you need to have popup on. What this will do is when you right click on your text object it will then add that popup and display it. This way you don't encounter that error. Solution that @BullyWillPlaza made is very good, rich and fast to implement in your program so you should try it our see how you like it.

为需要弹出窗口的文本对象制作这样的鼠标侦听器。这将做的是当您右键单击文本对象时,它将添加该弹出窗口并显示它。这样你就不会遇到那个错误。@BullyWillPlaza 制作的解决方案非常好、丰富且可以在您的程序中快速实现,因此您应该尝试一下,看看您喜欢它。