2012-11-27 51 views
2

我发现在Mac OS X中运行Java程序时,如果使用密钥,文本字段对象(例如JField)支持使用系统剪贴板进行剪切,复制和粘贴操作命令不需要你做额外的编码。例如,我可以创建一个JField,键入一些文本,选择它,然后使用“Command-C”将其复制,然后将其粘贴到另一个应用程序中。粘贴从其他应用程序复制的文本的作品相同。用于系统剪贴板操作的右键菜单项

我真的很喜欢Java自动执行此操作,但我注意到编辑菜单不会自动随剪切,复制和粘贴菜单项出现。当选择文本时,有没有办法自动添加这些菜单项以访问系统剪贴板?如果没有,那么实施它们的最好方法是什么,以便它像任何其他应用程序一样运行。在这一点上,我只对复制和粘贴文本感兴趣。

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

编辑︰我实际上想知道有关将此添加到菜单栏,但那里结束对下一个问题,我会有这样一个伟大的答案,我决定我会选择它作为正确的答案并重命名该问题。

回答

2

不幸的是,Swing不支持弹出上下文菜单。你必须推出自己的。幸运的是,这并不难。最简洁的方法可能是安装您自己的事件队列,如here所述。这篇文章提出如下实施:

// @author Santhosh Kumar T - [email protected] 
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()); 

    ..... 
} 

随着代码的一条线,你在你的应用程序的所有文本组件上的弹出菜单。

动作类不是太复杂。举例来说,这里的粘贴动作的执行情况,其中显示了与系统剪贴板交互:

// @author Santhosh Kumar T - [email protected] 
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; 
    } 
} 

看到这篇文章的代码,其他的操作实现。

+0

+1,你的方法更清洁,因为它自动处理* all *文本组件的菜单,而我的需要单独添加处理程序。 – Vulcan

+0

我喜欢这种方法,但是我在您链接的文章的评论中看到,至少有一个人非常反对这种方法,因为如果事情在未来版本中发生变化,更改事件队列可能会使整个应用程序崩溃的Java。但如果文章是在2005年编写的,代码仍然有效......这是否意味着它可以安全使用? – Thunderforge

+1

@Thunderforge - Java 1.7中显然存在一个关于安装新事件队列的错误。请参阅[此回复](http://stackoverflow.com/a/8965448/535871)以了解详细信息以及如何处理它。除此之外,我有充分理由相信这种方法是安全的。文章评论中的担忧似乎表明,拖放可能会导致问题。您可以轻松编写一个小应用程序来测试此问题。 –

1

您需要为此创建一个自定义弹出菜单,这可以通过使用MouseListener(或MouseAdapter)和JPopupMenu来完成。我的方法是创建一个可以添加到任何文本组件的自定义鼠标侦听器。

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 
     } 
    } 
} 

然后,你只需要添加一个ClipboardMenuHandler作为监听器的文本组件。

JTextField field = new JTextField(); 
ClipboardMenuHandler menuHandler = new ClipboardMenuHandler(field); 
field.addMouseListener(menuHandler); 
0

这工作对我来说:

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

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

现在,我只是用MyTextField无论我本来使用JTextField

相关问题