【问题标题】:Java: use clipboard to copy-paste java objects between different instances of same applicationJava:使用剪贴板在同一应用程序的不同实例之间复制粘贴 java 对象
【发布时间】:2013-01-11 20:53:04
【问题描述】:

我正在尝试在同一应用程序的不同实例之间实现对象的复制粘贴。目前它只适用于一个应用程序(我的意思是在同一个应用程序实例中复制和粘贴),但在不同实例之间不起作用。

复制代码:

// MyObject is a class of objects I want to copy/paste;
// MyObjectSelection is a class that impements Transferable and ClipboardOwner interfaces

Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
MyObject data = new MyObject(selectedItems);
MyObjectSelection dataSelection = new MyObjectSelection(data);
clipboard.setContents(dataSelection, this);

之后,我可以检查剪贴板的内容,如下所示:

Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable clipboardContent = clipboard.getContents(this);

DataFlavor[] flavors = clipboardContent.getTransferDataFlavors();
System.out.println("flavors.length=" + flavors.length);
for (int i = 0; i < flavors.length; i++){
   System.out.println("flavor=" + flavors[i]);
}

如果我从复制对象的同一个应用程序实例中执行此操作,它可以工作:flavors.length1,mimetype 是 application/x-java-serialized-object,而且,它可以工作。

但是如果我打开应用程序,执行复制,然后再次打开同一个应用程序(第一个没有关闭,即两个实例同时运行),并尝试从那里检查剪贴板内容,那么flavors.length 是@987654331 @。

我检查了文档和这些示例:onetwo,但我仍然找不到我的实现中的问题。

我错过了什么吗?


UPD:我添加了 sscce:clipboard_test.zip

这是一个带有 3 个源文件的测试应用程序(我使用 Eclipse 构建它):

  • ClipboardTest.java - 主应用类
  • MyObject.java - 用于复制/粘贴对象的类(该类仅包含 String 数组)
  • MyObjectSelection.java - 实现TranserableClipboardOwner 接口的类

    有两个按钮:“复制”、“测试”。

    当您按下“复制”按钮时,会创建 MyObject 的新实例 并放入剪贴板。

    当您按下“测试”按钮时,会检查剪贴板内容 并回显到控制台(支持的DataFlavor 的计数,以及每个DataFlavor

    所以,重复这些步骤:

  • 启动应用程序

  • 按“复制”按钮:您将在日志中看到"object copied" 消息
  • 按“测试”按钮:您将看到剪贴板的内容:

       flavors.length = 1
       flavor[0] = java.awt.datatransfer.DataFlavor[mimetype=application/x-java-serialized-object;representationclass=MyObject]
    
  • 启动另一个应用程序实例(不要关闭第一个)

  • 按下“测试”按钮:你会看到剪贴板是空的:

       flavors.length = 0
    

这是为什么呢?


UPD2: sscce 直接在此处发布:

  import java.awt.BorderLayout;

  import java.awt.datatransfer.Clipboard;
  import java.awt.datatransfer.ClipboardOwner;
  import java.awt.datatransfer.DataFlavor;
  import java.awt.datatransfer.Transferable;
  import java.awt.datatransfer.UnsupportedFlavorException;

  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;

  import java.awt.Toolkit;

  import javax.swing.JButton;
  import javax.swing.SwingUtilities; 
  import javax.swing.JFrame;

  public final class ClipboardTest implements Runnable, ClipboardOwner {

     public static void main(String[] args) {
        SwingUtilities.invokeLater (new ClipboardTest());
     } 

     public void run() {

        JFrame f = new JFrame ("Clipboard test");
        f.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE);

        //-- Create "copy" button.
        //   When you click it, new object "test_items" becomes created
        //   and put to the clipboard.
        {
           JButton button_copy = new JButton("copy");
           button_copy.addActionListener(new ActionListener(){
              public void actionPerformed(ActionEvent e){

                 String[] test_items = {
                    "one", "two", "three"
                 };

                 Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                 MyObject data = new MyObject(test_items);
                 MyObjectSelection dataSelection = new MyObjectSelection(data);
                 clipboard.setContents(dataSelection, ClipboardTest.this);

                 System.out.println("object copied");
              }
           });
           f.add(button_copy, BorderLayout.NORTH);
        }

        //-- Create "test" button.
        //   When you click it, clipboard contents are checked
        //   and echoed to the console (count of supported DataFlavor's, and each DataFlavor)
        {
           JButton button_test = new JButton("test");
           button_test.addActionListener(new ActionListener(){
              public void actionPerformed(ActionEvent e){

                 Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                 Transferable clipboardContent = clipboard.getContents(this);

                 DataFlavor[] flavors = clipboardContent.getTransferDataFlavors();
                 System.out.println("flavors.length = " + flavors.length);
                 for (int i = 0; i < flavors.length; i++){
                    System.out.println("flavor[" + i + "] = " + flavors[i]);
                 }

              }
           });
           f.add(button_test, BorderLayout.SOUTH);
        }

        f.pack();
        f.setVisible(true);
     }



     // ClipboardOwner implementation

     @Override
     public void lostOwnership(Clipboard clipboard, Transferable transferable){
        System.out.println("ClipboardTest: Lost ownership");
     }







     /* *****************************************************************************************
      * Object that I want to copy/paste
      * ****************************************************************************************/

     public static class MyObject {

        private String[] items;

        public MyObject(String[] items){
           this.setItems(items);
        }

        public String[] getItems(){
           return this.items;
        }

        public void setItems(String[] items){
           this.items = items;
        }

     }




     public static class MyObjectSelection implements Transferable, ClipboardOwner {

        private static DataFlavor dmselFlavor = new DataFlavor(MyObject.class, "Test data flavor");
        private MyObject selection;



        public MyObjectSelection(MyObject selection){
           this.selection = selection;
        }


        // Transferable implementation

        @Override
        public DataFlavor[] getTransferDataFlavors(){
           System.out.println("getTransferDataFlavors");
           DataFlavor[] ret = {dmselFlavor};
           return ret;
        }

        @Override
        public boolean isDataFlavorSupported(DataFlavor flavor){
           return dmselFlavor.equals(flavor);
        }

        @Override
        public synchronized Object getTransferData (DataFlavor flavor)
           throws UnsupportedFlavorException 
        {
           if (isDataFlavorSupported(flavor)){
              return this.selection;
           } else {
              throw new UnsupportedFlavorException(dmselFlavor);
           }
        }



        // ClipboardOwner implementation

        @Override
        public void lostOwnership(Clipboard clipboard, Transferable transferable){
           System.out.println("MyObjectSelection: Lost ownership");
        }

     }

  }

【问题讨论】:

  • 如需尽快获得更好的帮助,请发帖SSCCE
  • 操作系统和JVM的启动参数/配置对访问全局剪贴板也有很大的影响
  • @AndrewThompson,我添加了它,检查我更新的问题。
  • 如果 SSCCE 足够短,可以直接在论坛上发帖,请执行此操作。我不是为了帮助你而下载 Zip。
  • "(省略导入)" 我一般认为导入应该包含在 SSCCE 中。一个 SSCCE 也应该是 1 个源文件(即使一个源文件中有多个类)。

标签: java awt clipboard copy-paste


【解决方案1】:

引用this tutorial:

使用此机制传输数据使用Object 序列化,因此您用于传输数据的类必须实现Serializable 接口,使用它进行序列化的任何东西都必须实现。如果所有内容都不可序列化,您将在拖放或复制到剪贴板期间看到NotSerializableException

你的MyObject 不是Serializable,所以它不能工作。该框架显然检测到了这一事实(与可序列化父类的不可序列化子类的情况相反,或者仅在进程中检测到不可序列化的类似情况),因此它甚至不会为其他进程提供这种风格。

一般来说,同一个java应用程序的两个实例不会有相同的地址空间,所以它们不能简单地访问彼此的内存。因此,您传输的所有内容都必须序列化。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多