非文本组件中的 CCP

如果要使用不是文本组件之一的 Swing 组件之一来实现剪切,复制和粘贴,则必须进行一些附加设置。首先,您需要在动作图中安装剪切,复制和粘贴动作。以下方法显示了如何执行此操作:

private void setMappings(JList list) { 
        ActionMap map = list.getActionMap();
        map.put(TransferHandler.getCutAction().getValue(Action.NAME),
                TransferHandler.getCutAction());
        map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
                TransferHandler.getCopyAction());
        map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
                TransferHandler.getPasteAction());

设置“编辑”菜单时,例如,您还可以选择添加菜单加速器,以便用户可以键入 Control-C 来启动副本。在以下代码段中,粗体文本显示了如何为剪切操作设置菜单加速器:

menuItem = new JMenuItem("Cut");
    menuItem.setActionCommand((String)TransferHandler.getCutAction().
             getValue(Action.NAME));
    menuItem.addActionListener(actionListener);
    menuItem.setAccelerator(
      KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK));
    menuItem.setMnemonic(KeyEvent.VK_T);
    mainMenu.add(menuItem);

如果已为 CCP 操作设置了菜单加速器,则此下一步是多余的。如果尚未设置菜单加速器,则需要将 CCP 绑定添加到 ImportingMap。以下代码片段显示了如何完成此操作:

// only required if you have not set the menu accelerators
    InputMap imap = this.getInputMap();
    imap.put(KeyStroke.getKeyStroke("ctrl X"),
        TransferHandler.getCutAction().getValue(Action.NAME));
    imap.put(KeyStroke.getKeyStroke("ctrl C"),
        TransferHandler.getCopyAction().getValue(Action.NAME));
    imap.put(KeyStroke.getKeyStroke("ctrl V"),
        TransferHandler.getPasteAction().getValue(Action.NAME));

一旦安装了绑定并设置了“编辑”菜单,便要解决另一个问题:当用户启动剪切,复制或粘贴操作时,哪个组件应该执行该操作?对于文本组件,DefaultEditorKit会记住上一个组件具有焦点的位置,并将操作转发给该组件。下面的类TransferActionListener对非文本 Swing 组件执行相同的功能。此类可以放入大多数任何应用程序中:

public class TransferActionListener implements ActionListener,
                                              PropertyChangeListener {
    private JComponent focusOwner = null;

    public TransferActionListener() {
        KeyboardFocusManager manager = KeyboardFocusManager.
           getCurrentKeyboardFocusManager();
        manager.addPropertyChangeListener("permanentFocusOwner", this);
    }

    public void propertyChange(PropertyChangeEvent e) {
        Object o = e.getNewValue();
        if (o instanceof JComponent) {
            focusOwner = (JComponent)o;
        } else {
            focusOwner = null;
        }
    }

    public void actionPerformed(ActionEvent e) {
        if (focusOwner == null)
            return;
        String action = (String)e.getActionCommand();
        Action a = focusOwner.getActionMap().get(action);
        if (a != null) {
            a.actionPerformed(new ActionEvent(focusOwner,
                                              ActionEvent.ACTION_PERFORMED,
                                              null));
        }
    }
}

最后,您必须决定如何处理粘贴。在拖放的情况下,将数据插入放置位置。在粘贴的情况下,用户无法获得指向所需粘贴位置的好处。您需要确定什么对您的应用程序有意义–在当前选择之前或之后插入数据可能是最好的解决方案。

以下演示 ListCutPaste 演示了如何在JList实例中实现 CCP。从屏幕快照中可以看到,有三个列表,您可以在任何一个列表中剪切,复制和粘贴。它们还支持拖放。对于此演示,粘贴的数据将在当前选择之后插入。如果没有当前选择,则将数据追加到列表的末尾。

ListCutPaste 演示的快照。

Try this:

  • 单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 ListCutPaste。另外,要自己编译和运行示例,请查阅example index

  • 在列表之一中选择一个项目。使用“编辑”菜单或等效的键盘从源中剪切或复制列表项。

  • 选择要粘贴项 Object 列表项目。

  • 使用菜单或等效的键盘粘贴文本。在当前选择之后粘贴该项目。

  • 使用拖放执行相同的操作。