【问题标题】:How do I create a right click context menu in Java Swing?如何在 Java Swing 中创建右键单击上下文菜单?
【发布时间】:2010-10-20 11:58:03
【问题描述】:

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

【问题讨论】:

    标签: java swing contextmenu jpopupmenu


    【解决方案1】:

    您可能在菜单上手动调用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() 方法。

    【讨论】:

    • 使用上面的代码后,我收到错误消息“类型Figure中的方法addMouseListener(MouseListener)不适用于参数(PopClickListener)”问候,Vinay
    • @user1035905 你确定PopClickListener 扩展了MouseAdapter
    • 如何让它与键盘上的上下文菜单键一起工作?
    • 该解决方案优于 kleopatra 的唯一情况是当您需要一些自定义逻辑发生时(例如,不同条件下的不同弹出菜单);仍然,您必须添加键盘侦听器才能使用上下文菜单键
    • component 代表什么?
    【解决方案2】:

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

    目前在Swing中设置popupMenu的api是

    myComponent.setComponentPopupMenu(myPopupMenu);
    

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

    myChild.setInheritsPopupMenu(true);
    

    【讨论】:

    • @user681159 什么都不知道 - 而且不需要,IMO,只需阅读 api 文档 :-)
    • 您如何将它与JTable 一起使用,以便它在所选行或您右键单击的行上弹出?还是在这种情况下要选择旧方法?
    • @Burfee 或者通过子类化增强 JTable:覆盖 getPopupLocation(..) 并存储位置以供以后使用,see a recent QA 在所有 SwingX 集合组件中实现
    • @RanjitVamadevan 您认为哪里需要格式化?
    【解决方案3】:

    The Java TutorialsHow to Use Menus 文章中有一个关于Bringing Up a Popup Menu 的部分解释了如何使用JPopupMenu 类。

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

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

    【讨论】:

      【解决方案4】:

      以下代码实现了从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 在所有平台上正常工作。
      • key-listener 中的另一个错误:pressedEvent.getModifiersEx() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() 这些必须是 Ex 或不是 ExgetMenuShortcutKeyMask()Ex 版本仅在 java 10+ 之后可用。
      【解决方案5】:

      我将更正@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 并创建新实例。
      猜你喜欢
      • 2021-04-03
      • 2013-02-11
      • 2012-12-09
      • 2011-10-10
      • 1970-01-01
      • 2010-10-05
      • 2016-02-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多