Java:使用剪贴板在同一应用程序的不同实例之间复制粘贴java对象
我试图在同一个应用程序的不同实例之间实现对象的复制粘贴。 目前它只能在一个应用程序中工作(我的意思是,在同一个应用程序实例中复制和粘贴),但在不同的实例之间不起作用。
复制代码:
// 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.length
是1
,mimetype是application/x-java-serialized-object
,而且,它有效。
但是如果我打开应用程序,执行复制,然后再次打开相同的应用程序(第一个没有关闭,即两个实例同时运行),并尝试从那里检查剪贴板内容,然后flavors.length
为0
。
我检查了文档和这些例子: 一 , 二 ,但我仍然无法找到我的实现中的错误。
我错过了什么?
UPD:我添加了sscce: clipboard_test.zip 。
这是测试应用程序(我使用Eclipse构建它),包含3个源文件:
-
ClipboardTest.java
– 主app类 -
MyObject.java
– 要复制/粘贴的对象的类(此类仅包含String
数组) -
MyObjectSelection.java
– 实现Transerable
和ClipboardOwner
接口的类有两个按钮:“复制”,“测试”。
按“复制”按钮时,将创建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"); } } }
引用本教程 :
使用此机制传输数据使用
Object
序列化,因此用于传输数据的类必须实现Serializable
接口,因为必须使用它序列化。 如果所有内容都不可序列化,您将在删除或复制到剪贴板期间看到NotSerializableException
。
您的MyObject
不可Serializable
,因此无法工作。 框架显然检测到这一事实(与可序列化父类的不可序列化子类的情况相反,或者仅在进程中检测到不可序列化的类似情况),因此它甚至不会向其他进程提供这种风格。
通常,同一个Java应用程序的两个实例不会具有相同的地址空间,因此它们不能简单地访问彼此的内存。 因此,您传输的所有内容都必须序列化。