【发布时间】:2010-10-20 11:58:03
【问题描述】:
我目前正在通过在右键单击时实例化一个新的JMenu 并将其位置设置为鼠标位置来创建右键单击上下文菜单...有没有更好的方法?
【问题讨论】:
标签: java swing contextmenu jpopupmenu
我目前正在通过在右键单击时实例化一个新的JMenu 并将其位置设置为鼠标位置来创建右键单击上下文菜单...有没有更好的方法?
【问题讨论】:
标签: java swing contextmenu jpopupmenu
您可能在菜单上手动调用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());
当然,教程有slightly more in-depth的解释。
注意:如果您发现弹出菜单与用户单击的位置相去甚远,请尝试对 x 和 y 坐标使用 e.getXOnScreen() 和 e.getYOnScreen() 方法。
【讨论】:
PopClickListener 扩展了MouseAdapter?
component 代表什么?
这个问题有点老了 - 答案也是如此(以及教程)
目前在Swing中设置popupMenu的api是
myComponent.setComponentPopupMenu(myPopupMenu);
这样,鼠标和键盘触发器都会自动显示(后者取决于 LAF)。此外,它支持在容器的子项中重复使用相同的弹出窗口。要启用该功能:
myChild.setInheritsPopupMenu(true);
【讨论】:
JTable 一起使用,以便它在所选行或您右键单击的行上弹出?还是在这种情况下要选择旧方法?
在The Java Tutorials 的How to Use Menus 文章中有一个关于Bringing Up a Popup Menu 的部分解释了如何使用JPopupMenu 类。
教程中的示例代码展示了如何将MouseListeners 添加到应该显示弹出菜单的组件中,并相应地显示菜单。
(您描述的方法与教程介绍在组件上显示弹出菜单的方式非常相似。)
【讨论】:
以下代码实现了从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。 getMenuShortcutKeyMask() 的 Ex 版本仅在 java 10+ 之后可用。
我将更正@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 制作的解决方案非常好,丰富且快速地在您的程序中实施,因此您应该尝试一下,看看您喜欢它。
【讨论】: