11.9.4 使用本地剪贴板传递对象引用

11.9.4 使用本地剪贴板传递对象引用

本地剪贴板可以保存任何类型的Java对象,包括自定义类型的对象。为了将任意类型的Java对象保存到剪贴板中,DataFlavor里提供了一个javaJVMLocalObjectMimeType的常量,该常量是一个MIME类型字符串:application/x-java-jvm-local-Objectref,将Java对象放入本地剪贴板中必须使用该MIME类型。该MIME类型表示仅将对象引用复制到剪贴板中,对象引用只有在同一个虚拟机中才有效,所以只能使用本地剪贴板。创建本地剪贴板的代码如下:

1
Clipboard clipboard = new Clipboard("cp");

创建本地剪贴板时需要传入一个字符串,该字符串是剪贴板的名字,通过这种方式允许在一个程序中创建本地剪贴板,就可以实现像Word那种多次复制,选择剪贴板粘贴的功能。

本地剪贴板是JVM负责维护的内存区,因此本地剪贴板会随虚拟机的结束而销毁。因此一旦Java程序退出,本地剪贴板中的内容将会丢失

程序示例 定义Transferable接口实现类

Java并没有提供封装对象引用Transferable实现类,因此必须自己实现该接口。实现该接口与前面的ImageSelection基本相似,一样要实现该接口的三个方法,并持有某个对象的引用。看如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import java.awt.datatransfer.*;

public class LocalObjectSelection implements Transferable {
// 持有一个对象的引用
private Object obj;

public LocalObjectSelection(Object obj) {
this.obj = obj;
}

// 返回该Transferable对象支持的DataFlavor
public DataFlavor[] getTransferDataFlavors() {
DataFlavor[] flavors = new DataFlavor[2];
// 获取被封装对象的类型
Class clazz = obj.getClass();
String mimeType = "application/x-java-jvm-local-objectref;" + "class=" + clazz.getName();
try {
flavors[0] = new DataFlavor(mimeType);
flavors[1] = DataFlavor.stringFlavor;
return flavors;
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}

// 取出该Transferable对象封装的数据
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
if (!isDataFlavorSupported(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
if (flavor.equals(DataFlavor.stringFlavor)) {
return obj.toString();
}
return obj;
}

public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(DataFlavor.stringFlavor) || flavor.getPrimaryType().equals("application")
&& flavor.getSubType().equals("x-java-jvm-local-objectref")
&& flavor.getRepresentationClass().isAssignableFrom(obj.getClass());
}
}

上面程序创建了一个DataFlavor对象,用于表示本地Person对象引用的数据格式。创建DataFlavor对象可以使用如下构造器。

  • DataFlavor(String mimeType):根据mimeType字符串构造DataFlavor。

程序使用上面构造器创建了MIME类型为"application/x-java-jvm-local-objectref;class="+clazz.getName()的DataFlavor对象,它表示封装本地对象引用的数据格式。

有了上面的LocalObjectSelection封装类后,就可以使用该类来封装某个对象的引用,从而将该对象的引用放入本地剪贴板中。下面程序示范了如何将一个Person对象放入本地剪贴板中,以及从本地剪贴板中读取该Person对象。

public class CopyPerson
{
    Frame f = new Frame("复制对象");
    Button copy = new Button("复制");
    Button paste = new Button("粘贴");
    TextField name = new TextField(15);
    TextField age = new TextField(15);
    TextArea ta = new TextArea(3 , 30);
    // 创建本地的剪贴板
    Clipboard clipboard = new Clipboard("cp");
    public void init()
    {
        Panel p = new Panel();
        p.add(new Label("姓名"));
        p.add(name);
        p.add(new Label("年龄"));
        p.add(age);
        f.add(p , BorderLayout.NORTH);
        f.add(ta);
        Panel bp = new Panel();
        // 为“复制”按钮添加事件监听器
        copy.addActionListener(e -> copyPerson());
        // 为“粘贴”按钮添加事件监听器
        paste.addActionListener(e ->
        {
            try
            {
                readPerson();
            }
            catch (Exception ee)
            {
                ee.printStackTrace();
            }
        });
        bp.add(copy);
        bp.add(paste);
        f.add(bp , BorderLayout.SOUTH);
        f.pack();
        f.setVisible(true);
    }
    public void copyPerson()
    {
        // 以name,age文本框的内容创建Person对象
        Person p = new Person(name.getText()
            , Integer.parseInt(age.getText()));
        // 将Person对象封装成LocalObjectSelection对象
        LocalObjectSelection ls = new LocalObjectSelection(p);
        // 将LocalObjectSelection对象放入本地剪贴板
        clipboard.setContents(ls , null);
    }
    public void readPerson()throws Exception
    {
        // 创建保存Person对象引用的DataFlavor对象
        DataFlavor peronFlavor = new DataFlavor(
            "application/x-java-jvm-local-objectref;class=Person");
        // 取出本地剪贴板内的内容
        if (clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor))
        {
            Person p = (Person)clipboard.getData(peronFlavor);
            ta.setText(p.toString());
        }
    }
    public static void main(String[] args)
    {
        new CopyPerson().init();
    }
}

上面程序中的两段粗体字代码实现了复制、粘贴对象的功能,这两段代码与前面复制、粘贴图像的代码并没有太大的区别,只是前面程序使用了Java本身提供的Data.imageFlavor数据格式,而此处必须自己创建一个DataFlavor,用以表示封装Person引用的DataFlavor。运行上面程序,在“姓名”文本框内随意输入一个字符串,在“年龄”文本框内输入年龄数字,然后单击“复制”按钮,就可以将根据两个文本框的内容创建的Person对象放入本地剪贴板中;单击“粘贴”按钮,就可以从本地剪贴板中读取刚刚放入的数据,如图11.36所示。

图11.36将本地对象复制到本地剪贴板中

上面程序中使用的Person类是一个普通的Java类,该Person类包含了name和age两个成员变量,并提供了一个包含两个参数的构造器,用于为这两个Field成员变量;并重写了toString()方法,用于返回该Person对象的描述性信息。关于Person类代码可以参考codes\11\11.9\CopyPerson.java文件。