2017-08-22 17 views
0

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

这是映射,我终于成功地添加为的this帮助一个通用的规则,通过认识到某些组件使用“复制”的MAC版本,而其他人使用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); 

因此,我看到菜单项,但它不会复制任何内容,尽管映射到相同操作的快捷键不会复制。我甚至可以定义快捷键(我似乎必须定义自己,但也只是作为一个用户,这些东西有某种联系在一起的暗示):

int MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); 
KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_C, MASK); 
item.setAccelerator(keyStroke); 

所以,我缺少什么?我甚至想专门定义的动作侦听器,但无济于事:

item.addActionListener(myTable.getActionForKeyStroke(keyStroke)); 

听起来很可笑的是,键盘快捷方式自动工作(我必须弄清楚如何使苹果代替Ctrl键的加利福尼亚 - 重点工作(只花了几个小时)),现在我不能让菜单条目与现有的动作无关(即使工作了几个小时)。

+0

参见[*什么是JTable中CTRL + C事件的名字?*](https://stackoverflow.com/q/14356859/230513)的一些替代品。 – trashgod

+0

嗯,似乎myTable.getInputMap()。get(KeyStroke.getKeyStroke(KeyEvent.VK_C,MASK))给出'null'。但“copy”是actionMap中的名称,而actionMap.get(“copy”)会提供有效的Action。 –

+0

您忘记了'WHEN_ANCESTOR_OF_FOCUSED_COMPONENT'。 – trashgod

回答

1

要从comments回顾一下,这里有一个全面实施改性从文章中引用originalhere - 附的addCopyAndSelectAll方法,增加了一个标准的“复制”和“全选”菜单项。请注意,这主要适用于JTable控件,因为它们使用这些操作名称。其他组件类型可能会初始化为其他动作名称,如我在the other issue的回答中所述。

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; 
    } 
} 
相关问题