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