2017-08-22 18 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; 
    } 
} 
相關問題