Java 右键单击用于系统剪贴板操作的菜单项

Java 右键单击用于系统剪贴板操作的菜单项,java,clipboard,menuitem,Java,Clipboard,Menuitem,我发现,在Mac OS X中运行Java程序时,如果您使用键命令而无需额外编码,则文本字段对象(例如JField)支持使用系统剪贴板执行剪切、复制和粘贴操作。例如,我可以创建一个JField,输入一些文本,选择它,然后使用“Command-C”复制它,然后将它粘贴到另一个应用程序中。这同样适用于粘贴从其他应用程序复制的文本 我真的很喜欢Java自动完成这项工作,但我注意到编辑菜单不会自动显示剪切、复制和粘贴菜单项。是否有任何方法可以在选择文本时自动添加这些菜单项以访问系统剪贴板?如果没有,那么实

我发现,在Mac OS X中运行Java程序时,如果您使用键命令而无需额外编码,则文本字段对象(例如JField)支持使用系统剪贴板执行剪切、复制和粘贴操作。例如,我可以创建一个JField,输入一些文本,选择它,然后使用“Command-C”复制它,然后将它粘贴到另一个应用程序中。这同样适用于粘贴从其他应用程序复制的文本

我真的很喜欢Java自动完成这项工作,但我注意到编辑菜单不会自动显示剪切、复制和粘贴菜单项。是否有任何方法可以在选择文本时自动添加这些菜单项以访问系统剪贴板?如果没有,那么实现它们的最佳方式是什么,以使其与任何其他应用程序一样工作。现在,我只对复制和粘贴文本感兴趣

另外,我知道系统剪贴板是特定于平台的。文本字段对象的自动系统剪贴板功能是否出现在其他平台上


编辑:实际上我想知道如何将此添加到菜单栏,但下一个问题的答案非常棒,我决定选择它作为正确答案并重命名该问题。

不幸的是,Swing不支持弹出式上下文菜单。你必须自己滚。幸运的是,这并不难。也许最干净的方法是安装您自己的事件队列,如下所述。该条建议采取以下措施:

// @author Santhosh Kumar T - santhosh@in.fiorano.com 
public class MyEventQueue extends EventQueue{ 
    protected void dispatchEvent(AWTEvent event){ 
        super.dispatchEvent(event); 

        // interested only in mouseevents 
        if(!(event instanceof MouseEvent)) 
            return; 

        MouseEvent me = (MouseEvent)event; 

        // interested only in popuptriggers 
        if(!me.isPopupTrigger()) 
            return; 

        // me.getComponent(...) retunrs the heavy weight component on which event occured 
        Component comp = SwingUtilities.getDeepestComponentAt(me.getComponent(), me.getX(), me.getY()); 

        // interested only in textcomponents 
        if(!(comp instanceof JTextComponent)) 
            return; 

        // no popup shown by user code 
        if(MenuSelectionManager.defaultManager().getSelectedPath().length>0) 
            return; 

        // create popup menu and show 
        JTextComponent tc = (JTextComponent)comp; 
        JPopupMenu menu = new JPopupMenu(); 
        menu.add(new CutAction(tc)); 
        menu.add(new CopyAction(tc)); 
        menu.add(new PasteAction(tc)); 
        menu.add(new DeleteAction(tc)); 
        menu.addSeparator(); 
        menu.add(new SelectAllAction(tc)); 

        Point pt = SwingUtilities.convertPoint(me.getComponent(), me.getPoint(), tc);
        menu.show(tc, pt.x, pt.y);
    } 
}
然后将其用于:

public static void main(String[] args){ 
    Toolkit.getDefaultToolkit().getSystemEventQueue().push(new MyEventQueue()); 

    .....
}
有了这一行代码,应用程序中的每个文本组件都会出现一个弹出菜单

actions类并不太复杂。例如,下面是粘贴操作的实现,它显示了与系统剪贴板的交互:

// @author Santhosh Kumar T - santhosh@in.fiorano.com 
class PasteAction extends AbstractAction{ 
    JTextComponent comp; 

    public PasteAction(JTextComponent comp){ 
        super("Paste"); 
        this.comp = comp; 
    } 

    public void actionPerformed(ActionEvent e){ 
        comp.paste(); 
    } 

    public boolean isEnabled(){ 
        if (comp.isEditable() && comp.isEnabled()){ 
            Transferable contents = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(this); 
            return contents.isDataFlavorSupported(DataFlavor.stringFlavor); 
        }else 
            return false; 
    } 
}

有关其他操作实现的代码,请参阅本文。

您需要为此创建一个自定义弹出菜单,可以使用(或)和。我的方法是创建一个自定义鼠标侦听器,您可以将其添加到任何文本组件中

public class ClipboardMenuHandler extends MouseAdapter {

    private final JTextComponent textComponent;

    public ClipboardMenuHandler(JTextComponent textComponent) {
        this.textComponent = textComponent;
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        if (e.isPopupTrigger()) 
            ClipboardMenu menu = new ClipboardMenu();
            menu.show(textComponent, e.getX(), e.getY());
        }
    }

    private class ClipboardMenu extends JPopupMenu {

        public ClipboardMenu() {
            // add copy/cut/paste actions; refer to Ted's answer for PasteAction
        }
    }
}
JTextField field = new JTextField();
ClipboardMenuHandler menuHandler = new ClipboardMenuHandler(field);
field.addMouseListener(menuHandler);
然后,您只需添加一个
剪贴簿MenuHandler
作为文本组件的侦听器

public class ClipboardMenuHandler extends MouseAdapter {

    private final JTextComponent textComponent;

    public ClipboardMenuHandler(JTextComponent textComponent) {
        this.textComponent = textComponent;
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        if (e.isPopupTrigger()) 
            ClipboardMenu menu = new ClipboardMenu();
            menu.show(textComponent, e.getX(), e.getY());
        }
    }

    private class ClipboardMenu extends JPopupMenu {

        public ClipboardMenu() {
            // add copy/cut/paste actions; refer to Ted's answer for PasteAction
        }
    }
}
JTextField field = new JTextField();
ClipboardMenuHandler menuHandler = new ClipboardMenuHandler(field);
field.addMouseListener(menuHandler);

这对我起了作用:

public class MyTextField extends JTextField {
    public static final MyPopupMenu POPUP_MENU = new MyPopupMenu();

    public MyTextField() {
        this.setComponentPopupMenu(POPUP_MENU);
    }
}

现在,我只要在任何地方使用
MyTextField
,否则我会使用
JTextField

+1,你的方法更干净,因为它会自动处理所有文本组件的菜单,而我的方法需要单独添加处理程序。我喜欢这种方法,但我在您链接的文章的评论中看到,至少有一个人非常反对这种方法,因为如果Java的未来版本发生变化,更改事件队列可能会导致整个应用程序崩溃。但是如果这篇文章是在2005年写的,并且代码仍然有效……这是否意味着使用它是安全的?@Thunderforge-显然Java 1.7中有一个关于安装新事件队列的bug。有关详细信息以及如何处理,请参阅。除此之外,我完全有理由相信这种方法是安全的。这篇文章评论中的担忧似乎表明拖放操作可能会导致问题。你可以很容易地编写一个小应用程序来测试这个问题。太好了,谢谢!实际上,我想知道如何将剪切、复制和粘贴添加到菜单栏,但这解决了我可能遇到的下一个问题。我想,只要修改代码,使其与菜单栏的行为相同。@BenC.R.Leggiero-这完全有道理,前提是您完全控制应用程序中所有
JTextField
-派生组件,并且可以自由地让它们都派生自
JTextField
扩展。情况并非总是如此,尤其是当您使用第三方库或代码生成工具时。不过,正如我所说,我当时对这个答案的灵感还有些模糊。