Java 如何将标准复制操作映射到Swing中的弹出菜单

Java 如何将标准复制操作映射到Swing中的弹出菜单,java,swing,Java,Swing,我对Swing UI有一个简单的愿望:有一个标准的复制操作映射到组件的InputMap。接下来,在同一个组件中有一个弹出菜单,我想添加一个运行复制操作的菜单项,当然会显示inputMap中的键盘快捷键 这是映射的mac版本,我最终在的帮助下将其作为一般规则添加,因为我意识到一些组件使用“copy”,而其他组件使用DefaultEditorKit.copyAction: inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.META

我对Swing UI有一个简单的愿望:有一个标准的复制操作映射到组件的
InputMap
。接下来,在同一个组件中有一个弹出菜单,我想添加一个运行复制操作的菜单项,当然会显示inputMap中的键盘快捷键

这是映射的mac版本,我最终在的帮助下将其作为一般规则添加,因为我意识到一些组件使用“copy”,而其他组件使用DefaultEditorKit.copyAction:

inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.META_DOWN_MASK), DefaultEditorKit.copyAction);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.META_DOWN_MASK), "copy");
现在,我可以找到表的操作,例如

ActionMap actionMap = myTable.getActionMap();
Action action = actionMap.get("copy");
现在,我使用操作创建菜单项:

JPopupMenu popupMenu = new JPopupMenu();
JMenuItem item = new JMenuItem(action);
popupMenu.add(item);
table.setComponentPopupMenu(popupMenu);
因此,我看到了菜单项,但它不会复制任何内容,尽管映射到同一操作的快捷键会复制。我甚至可以定义快捷方式(我似乎必须自己定义,但也只是为了提示用户这些东西是以某种方式链接在一起的):

那么,我错过了什么?我甚至试图明确定义动作监听器,但没有成功:

item.addActionListener(myTable.getActionForKeyStroke(keyStroke));
听起来很有趣,键盘快捷键可以自动工作(我只是想知道如何在Mac中使用Cmd键而不是Ctrl键(只花了几个小时),现在我根本无法将菜单项链接到现有操作(即使在工作了两个小时之后)。

从,下面是一个完整的实现,它是从文章中的修改而来,使用
addCopyAndSelectAll
方法添加了一个标准的“copy”和“selectAll”菜单项。请注意,这主要适用于
JTable
控件,因为它们使用这些操作名称。其他组件类型可能会初始化为其他操作名称,正如我在对的回答中提到的


请参阅以获取一些替代方法。嗯,似乎myTable.getInputMap().get(KeyStroke.getKeyStroke(KeyEvent.VK_C,MASK))给出了“null”。但是“copy”是actionMap中的名称,actionMap.get(“copy”)提供了一个有效的操作。你忘记了
当\u FOCUSED\u组件的\u祖先\u时。
。啊哈-不,我没有忘记-我不知道:)我承认,这是我第一次做任何相关的事情,所以我很挣扎,但我也没想到会有这么复杂的事情,任何一个好吧,现在我从InputMap中得到了“副本”,正如预期的那样。-问题仍然是:如何从代码或菜单项触发该操作,使其也能与鼠标操作一起工作?您可以尝试上面引用的@camickr方法。
item.addActionListener(myTable.getActionForKeyStroke(keyStroke));
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;

/*
 * The ActionMapAction class is a convenience class that allows you to use an installed Action as an
 * Action or ActionListener on a separate component.
 *
 * It can be used on components like JButton or JMenuItem that support an Action as a property of
 * the component. Or it can be added to the same above components as an ActionListener.
 *
 * The benefit of this class is that a new ActionEvent will be created such that the source of the
 * event is the component the Action belongs to, not the component that was "clicked". Otherwise in
 * many cases a ClassCastException will be thrown when the Action is invoked.
 */
@SuppressWarnings("serial")
public class ActionMapAction extends AbstractAction {
  /**
   * @param parent
   * @param popupMenu
   */
  public static void addCopyAndSelectAll(JComponent parent, JPopupMenu popupMenu) {
    // Must use ActionMapAction to link between the MenuItem and Table
    // The "copy" action, for example must be called from a Table, not from MenuItem
    Action copyAction = new ActionMapAction("Copy", parent, "copy");

    JMenuItem copyItem = new JMenuItem(copyAction);
    int MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
    copyItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, MASK));
    popupMenu.add(copyItem);

    Action selAction = new ActionMapAction(UiMessages.INSTANCE.get("Select All", parent, "selectAll");

    JMenuItem selItem = new JMenuItem(selAction);
    selItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, MASK));
    popupMenu.add(selItem);

    parent.setComponentPopupMenu(popupMenu);
  }

  private Action originalAction;
  private JComponent component;

  private String actionCommand = "";

  /**
   * Replace the default Action for the given KeyStroke with a custom Action
   *
   * @param name the name parameter of the Action
   * @param componet the component the Action belongs to
   * @param actionKey the key to identify the Action in the ActionMap
   */
  public ActionMapAction(String name, JComponent component, String actionKey) {
    super(name);

    originalAction = component.getActionMap().get(actionKey);

    if (originalAction == null) {
      String message = "no Action for action key: " + actionKey;
      throw new IllegalArgumentException(message);
    }

    this.component = component;
  }

  /**
   * Invoke the original Action using the original component as the source of the event.
   */
  @Override
  public void actionPerformed(ActionEvent e) {
    e = new ActionEvent(component, ActionEvent.ACTION_PERFORMED, actionCommand, e.getWhen(), e.getModifiers());

    originalAction.actionPerformed(e);
  }

  public void setActionCommand(String actionCommand) {
    this.actionCommand = actionCommand;
  }
}