位于上海,服务全国!

位于上海,服务全国!

如何编写Java剪贴板功能

作者:admin 分类: 时间:2017-06-30 14:35:41 点击量:941

剪贴板提供GUI最重要的功能之一,即剪切复制粘贴功能。 我们可以做的是从用户界面中选择一个元素(无论是文本段,图像,文件等等),并触发输入焦点组件的键盘操作。Java GUI提供的许多用户组件(如Swing或AWT)都内置了对此机制的支持。 这就是我们不需要在每个Java应用程序中明确地使用写死实现此功能的原因。 但是,如果我们想将此功能吸收到在Swing,AWT或JavaFX中开发的自定义用户组件中,则需要进行写死。 这可以在Java提供的API支持的帮助下完成。 本文重点介绍这个API,以提供如何在Java代码中实现它的功能。
总览
剪切复制粘贴功能简化了GUI组件之间的数据传输,但得借助剪贴板。通常发生的是,当我们通过用户组件发出剪切或复制命令时,数据会被提取到全局内存位置,其由底层平台的剪贴板管理器管理。正是因为这个原因,当我们从Swing文本字段中剪切或复制文本时,也可以使用任何其他Java或非Java应用程序(例如记事本)。可以提取文本的Java应用程序已经终止了,但是数据可通过粘贴命令被另一个应用程序使用。
Java提供了一个名为Clipboard的专用类,其在java.awt.datatransfer中定义。该类的实例用于引用称为剪贴板的系统资源。然而,在大多数情况下,通过使用其唯一的构造函数来直接实例化此类并不是必需的,因为我们可以通过java.awt包中定义的另一个类(称为Toolkit)的实例来获取它的引用。
该工具包是一个抽象超类,其中包含抽象窗口工具包的所有功能,并与本机窗口工具包实现的可用性(如滚动效果,窗口可见性,大小,模态等)绑定。因此,抽象窗口工具包与本地窗口的绑定使得GUI的行为与应用程序运行的平台不同。
获取剪贴板参考的最快方法是通过Toolkit。

JTextField textField=new JTextField(40);
Toolkit toolkit=textField.getToolkit();
或者,通过使用Toolkit类中定义的静态函数。
Toolkit toolkit=Toolkit.getDefaultToolkit();
Obtain the Clipboard reference as follows:

Clipboard clipboard=Toolkit
   .getDefaultToolkit().getSystemClipboard();
System clipboard
因此,剪贴板有助于各种Java的用户组件以及非Java应用程序之间无障碍的和简单的数据传输。由于通过剪切复制操作提取的数据可以是各种形式,例如文本段,丰富文档,图像,文件,图像元素等,这种简单的可用性具有相当的隐蔽性。数据存储在剪贴板中的方式对于它已经创建的应用程序具有很强的痕迹,并且对其可以粘贴到的其他用户组件具有决定性意义。例如,从Excel表单提取的一些数据可能会被粘贴到类似的应用程序,但显然不能粘贴到不了解格式的组件上。以相同的方式,从照片编辑应用程序提取的图片单元片段不能被粘贴到简单的文本应用程序,如记事本。
这意味着当我们从应用程序中提取数据时,它看起来似乎很简单,它也会复制剪贴板中数据的格式和其他信息。除了这个问题,即使简单的文本数据传输也是由许多字符集组成的。然而,从一个应用程序组件提取的数据可能与目标组件支持的字符集不一致。因为剪贴板是由底层平台管理的,所以其在这个问题上肯定有优势,但是运行在较高层的Java应用程序可能无法在这方面利用本地支持。
因此,当使用剪贴板资源时,我们应该记住,并不是所有的数据都可以无缝地转移,特别是当我们处理Java和其他原生应用程序时。
剪贴板类
现在,让我们来看看剪贴板类的功能。 这个类最常用的方法是setContents()和getContents()。 setContents()方法用于将剪贴板的内容设置为剪切复制操作,并使用getContents()方法从剪贴板中检索内容,如粘贴操作。

void setContents(Transferable contents,
   ClipboardOwner owner)
Transferable getContents(Object requestor)
在剪贴板中设置的数据包必须被包装在可传输对象中。 可传输接口在java.awt.datatransfer包中定义。 它主要用于提供转移操作的数据。 因此,传输到剪贴板和从剪贴板传输的每个数据包必须被封装在一个可传输实例中。 使用getContents()从Clipboard检索的数据也会收到一个Transferable对象。
ClipboardOwner,也是在java.awt.datatransfer中定义的一个接口,是剪贴板内容的所有者。 一旦其他数据覆盖剪贴板的内容,就会通知该对象。 任何在剪贴板中被覆盖的内容意味着ClipboardOwner对象已经失去了该内容的所有权。

Bear this in mind when experimenting with the following code that everything copied cannot be pasted everywhere. This is not the limitation of the Clipboard, but the limitation of the user components.
当从剪贴板检索内容时,应注意检查数据风格是否能被接收组件的支持。 否则,不匹配可能导致抛出UnsupportedFlavorException。
一个快速示例
假设我们要模拟一个字符串值的剪切或复制操作(类似于Ctrl + X或Ctrl + C)到剪贴板,并使用粘贴操作(Ctrl + V)从剪贴板中回收值,我们可以进行如下操作。 如前所述,数据或数据风格的格式在组件之间的数据传输中起着至关重要的作用。
请记住,以下实验代码的复制都无法粘贴到任何地方。 这不是剪贴板的限制,而是用户组件的限制。

package org.mano.example;

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
   java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

public class Main {

   public static void main(String[] args) {

      // This represents a cut-copy (Ctrl+X/Ctrl+C) operation.
      // The text will be copied to the clipboard
      // StringSelection is a Transferable implementation
      // class.

      StringSelection data = new StringSelection
         ("This is copied to the clipboard");
      Clipboard cb = Toolkit.getDefaultToolkit()
         .getSystemClipboard();
      cb.setContents(data, data);


      // This represents the paste (Ctrl+V) operation

      try {
         Transferable t = cb.getContents(null);
         if (t.isDataFlavorSupported(DataFlavor.stringFlavor))
            System.out.println(t.getTransferData(DataFlavor
               .stringFlavor));
      } catch (UnsupportedFlavorException | IOException ex) {
          System.out.println("");
      }
   }
}
结论
简短的说,这就是在Java中实现剪贴板功能所需要的全部。 Clipboard类定义了许多其他方法,但所有中心都围绕几个类,例如DataFlavor,Transferable和ClipboadOwner,并通过FlavorListeners事件类实现数据调用。 此外,如果要通过键盘事件启动Clipboard setContent和getContent方法,请考虑在Java中实现KeyStroke事件。