如何在 JavaSwing 中创建右击上下文菜单?

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

160569 次浏览

Java 教程如何使用菜单文章中有一个关于 弹出菜单的部分,解释了如何使用 JPopupMenu类。

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

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

您可能正在手动调用菜单上的 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.

要创建一个右击弹出菜单,只需创建一个 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 MouseListener to the components you would like the menu to popup for.

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 坐标。

这个问题有点老了——答案也是(教程也是)

当前在 Swing 中设置 popupMenu 的 API 是

myComponent.setComponentPopupMenu(myPopupMenu);

通过这种方式,鼠标和键盘触发器(后者取决于 LAF)都会自动显示。另外,它支持在容器的子级上重用相同的弹出窗口。为了实现这一功能:

myChild.setInheritsPopupMenu(true);

下面的代码使用复制、剪切、粘贴、选择全部、撤消和重做函数实现了 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);

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

我将纠正@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 提供的解决方案非常好,内容丰富,并且可以快速地在你的程序中实现,所以你应该尝试一下,看看你是否喜欢它。