Delo z odložiščem (clipboard)



 

This article will give you a good understanding of how to send and get information from the clipboard in Java. You'll also learn how to deal with the different data flavors available. Finally, we'll cover the multiple personalities of clipboards and how they provide support for more than one data flavor.

Java offers two types of clipboards: local and system. Local clipboards are only available inside the virtual machine that your applet or application is running. However, unlike some operating systems that limit you to only one clipboard, Java allows you to have as many local clipboards as you desire. Accessing a particular local clipboard is as easy as referring to it by name.

System clipboards are directly linked with the peer operating system, allowing your application to transfer information among any applications running under that operating system. One disadvantage of using the system clipboard is that you can only transfer text data. Other types of objects are not supported by the system clipboard. With any luck, this issue will be addressed in the next release of the JDK.

Before we go any further, let's take a look at all the classes involved in manipulating the clipboard. These classes, listed in the table below, are all part of the java.awt.datatransfer package.
 



List of all classes in the java.awt.datatransfer package

 
Name Type Description
Clipboard Class Deals with everything that is a transferable
ClipboardOwner Interface Every class that deals with the clipboard must implement this interface. This interface is used to notify when the data originally placed in the clipboard has been overwritten
Dataflavor Class Represents all the data types that transferable support
StringSelection Class One type of transferable that is supplied with Java
Transferable Interface Wrapper to objects passed to the clipboard
UnsupportedFlavor Exception Class Exception thrown by transferable for an unsupported data flavor
More on the clipboard classes
Let's go deeper into our exploration of the java.awt.datatransfer package by looking in detail at each class.

The Clipboard class
The Clipboard class is your link to accessing the clipboard. It includes three methods, which are defined in the following table:
 



Clipboard class

 
Method Description
String getName () Get the name of the clipboard
void setContents (Transferable, ClipboardOwner) Set the content of the clipboard along with owner object
Transferable getContent (Object) Get the content of the clipboard in the form of a Transferable object. The object passed as a parameter is the owner
The three Clipboard class methods above allow you to name the clipboard, send information to it, or get information from it. Accessing the system clipboard or creating a local clipboard is different and requires a bit more discussion. To access the system clipboard, assign a reference from the system clipboard to the Clipboard class, such as:
Clipboard clipboard = getToolkit ().getSystemClipboard ();
On the other hand, to create a local clipboard you only need to create a Clipboard object with the name that you want to assign to it, for example:
Clipboard clipboard = new Clipboard ("My first clipboard");
Accessing the system clipboard or creating a local clipboard is different but straightforward.

The ClipboardOwner interface
Because Java is a multiplatform language, and because operating systems behave differently toward clipboards, the authors of the Java language had to come up with a mechanism to deal with subtle differences. This is the reason for the presence of the ClipboardOwner interface. Its sole function is to inform the owner of the clipboard when his or her data is being overwritten by someone else. It can also signal an application when to release a resource associated with the data.

In a real application, the lostOwnership method could be used to set a flag that informs your application about the availability of the data in the clipboard. Microsoft Word, while not written in Java, is a good example of this mechanism at work in an application. Whenever you put something in the clipboard within Word and then quit, a dialog box appears informing you that data is in the clipboard. You will then be asked if you want to leave the data in the clipboard.

Implementing the ClipboardOwner interface is relatively straightforward because there is only one method to implement. This method will cause your program to relinquish ownership of the clipboard.

The DataFlavor class
The DataFlavor class is used to represent the type of an object. You're not limited to one data flavor (or type) per object. And, like us, your objects can have multiple personalities! For example, an image class can be represented as a Java class or as an array of bits (GIF, JPEG, and so on). In reality, a DataFlavor class is a wrapper to a MIME type. The MIME standard is extensive, hence there are virtually no limits to the data that can be transferred to the clipboard. (A discussion on the MIME standard is out of the scope of this article, but you can find additional information in the Resources section.)

As an example of a data flavor, you will find that the StringSelection class has two flavors based on MIME types. On implementation is "application/x-java-serialized-object", and the second is "text/plain; charset=unicode". In fact, this implementation is telling us that we can retrieve text from the clipboard as a String class (application/x-java-serialized-object) or as plain text (text/plain; charset=unicode).

There are two ways to create a DataFlavor. You can write:

public DataFlavor (representationClass, String humanRepresentationName)
This constructor will create a new data flavor that represents a Java class. The returned DataFlavor will have representationClass = representationClass and a mimeType = application/x-java-serialized-object. As an example, the following would create a DataFlavor for the java.awt.Button:
DataFlavor (Class.forName ("java.awt.Button"), "AWT Button");
Now, this second constructor
public DataFlavor (String mimeType, String humanRepresentationName)
will construct a DataFlavor using a MimeType. The returned DataFlavor will be based on the MimeType. If the MimeType is application/x-java-serialized-object, then the result will be the same as if you called the previous constructor. Nonetheless, the returned DataFlavor will be representationClass= InputStream and mimeType =mimeType. As an example, the following call would create a plain-text flavor:
public DataFlavor ("text/plain; charset=unicode", "Unicode");
The following table shows the methods of the DataFlavor class.
 



DataFlavor class

 
Methods Description
boolean equals (DataFlavor) Test if the DataFlavor supplied is equal to the DataFlavor represented by this class
String getHumanPresentableName () Return the human representable name for the format that this DataFlavor represents
void setHumanPresentableName (String) Set the human representation name for this DataFlavor
String getMimeType () Get the MIME type string represented by this DataFlavor
Class getRepresentationClass () Return the Class that represents this class
The Transferable interface
The Transferable interface must be implemented by all classes that you want to send to the clipboard, hence the Clipboard class will only understand classes that have been wrapped by the Transferable interface. The Transferable interface is comprised of three methods:
 



Transferable interface

 
Methods Description
DataFlavor getTransferDataFlavor () Return an array of DataFlavor that represents the object
boolean isDataFlavorSupported (DataFlavor) Test if the DataFlavor supplied is supported
Object getTransferData (DataFlavor) Return the object represented by the supplied DataFlavor
This concludes our tour of all the classes involved in handling the clipboard. We have seen that in order to access the clipboard we must either create a Clipboard object or obtain a reference to the system clipboard. Because the clipboard only accepts objects of type Transferable, the object that you want to send to the clipboard must implement this interface. Finally, all objects in the clipboard have flavors that are represented by the DataFlavor class, which in reality is a wrapper to MIME types.

In the next sections, we will put into practice what we have learned.

The recipe for clipboard utilization
How these various classes access the clipboard can be confusing. Fortunately, there is a simple recipe, which involves the following steps:

Step 1. Create a class called xxxxSelection. Here, xxx should name the type represented by this flavor. For example, ImageSelection would be a good name for an image flavor. This naming convention is merely a suggestion, of course. I'm following the established convention of use with the StringSelection provided in the JDK, but you can name this class anything you want. It's important to remember that this object must implement the Transferable and ClipboardOwner interfaces. If you are planning to transfer text, the StringSelection class should be used instead.

Step 2. Define a class to access the clipboard. To access a local clipboard, use the following call: Clipboard clipboard = new Clipboard ("name"). To access the peer operating system clipboard, use this call instead: Clipboard clipboard = getToolkit ().getSystemClipboard ().

Step 3. Set the content of the clipboard. To do this, use the setContent method in the Clipboard class, where the first parameter is an object that implements a Transferable (xxxxSelection class created in Step 1), and the second parameter is a reference to the class calling this method.

Step 4. Get the content of the clipboard. Use the getContent method in the Clipboard class. This method will return a class of type Transferable.

Step 5. Implement a 'cut operation'. To do this, you must manually erase the data once it is copied to the clipboard. Java provides no implementation of a cut operation.

After this brief tour of the classes involving clipboard manipulation, we'll follow the suggested recipe to write a simple applet that transfers text to the system clipboard.

Listing 1
Let's examine this applet:

Listing 1

The following is an explanation of specific lines of code in Listing 1.

Line 9: Define the class applet1 to extend the Applet class and implement the ClipboardOwner interface.

Line 17: Define a clipboard object.

Line 26: Set the clipboard object to the peer operating system clipboard.

Lines 45 to 47: Implement the only method in this interface. In this article we do not use the lostOwnership method but simply print a message on the console. You could experiment with this method by copying some text to the clipboard using this applet, and then copy something else from another application. You should see the lost ownership message appear in the Java console, because the data that was placed in the clipboard (using the Java applet) was overwritten by the other application.

Line 52: Define a class of the type StringSelection that implement a text data flavor. We then get the content of the source text field.

Line 53: Set the content of the clipboard to the fieldContent class that we defined on the previous line. Notice that we must supply the owner of this class, in this case, this applet.

Line 61: Define an object of type Transferable to receive the content of the clipboard.

Line 63: Validate two things. First, is the clipboard empty? Second, is the content of the clipboard the right flavor? In this case we are looking for a stringFlavor.

Line 67: Get the content of the clipboard in a string variable. To do this, we call the getTransferData method with the flavor required. In this case, we need a DataFlavor.stringFlavor type.

Line 69: Set the content of the destination text field to the content of the clipboard.

You can experiment with this applet by transferring text between this applet and another Java applet, or between a Java applet and a native program, like Notepad, for those running Microsoft Windows.

Listing 2
In the second example, we will write an applet that copies an image to the clipboard. The image will implement its own flavor.

Listing 2

The following is an explanation of specific lines of code in Listing 2.

Line 27: Create a clipboard object that references a local clipboard.

Line 41: Set the sourImage control to Image.gif.

Lines 44 to 50: Implement the lostOwnership method. We simply print a message on the Java console.

Line 6: Create an ImageSelection object based on the image in the sourceImage control.

Line 57: Set the content of the clipboard with the ImageSelection object.

Line 66: Get the content of the clipboard.

Line 68: Ensure that the content is not null and that the flavor we are looking for is supported.

Line 71: Get the data in the appropriate flavor.

Line 72: Set the destinationImage control to the content just obtained.

Line 90: Define the ImageSelection class.

Line 93: Define an array of DataFlavor called supportedFlavors with one element (imageFlavor).

Line 102: Create the image flavor. The flavor created is based on the java.awt.Image with the representation name "Image."

Lines 111 to 130: Implement the Transferable methods.

Line 123: Return the content of the clipboard with this method.

Line 125: Validate the flavor. If the requested flavor is supported, then the picture object is returned. Otherwise, an exception is thrown.

In Listing 1, we used the default data flavor (StringSelection) to send text to the system clipboard. In Listing 2, we went further by implementing our own data flavor java.awt.Image.

Implementing more than one flavor
At this point, we have worked only with objects that support one flavor. We could modify the preceding example and add a bitmap flavor. The following listing shows the required modifications:

Listing 3

The class that required major modifications was the ImageSelection class. The following additions were made to the original version:

Line 11: Create a new object to represent the bitmap flavor.

Line 13: Add the bitmapFlavor to the array of available flavors.

Line 22: Create the bitmapFlavor with a MIME type of image/gif.

Lines 47 to 49: Modify the if statement for the new flavor (bitmapFlavor). If the flavor requested is a bitmapFlavor, then a call is made to the getBitmapOfImage method. This method will return an array on int representing each pixel.

You may have noticed that we did not supply the implementation for the paste operation. It is left to the reader as an exercise.

Conclusion
In this tip, we have seen that in order to use the clipboard we need a Clipboard object. Also, data sent to the clipboard must implement the Transferable interface. And all data in the clipboard must have one or more flavors that are defined by the DataFlavor class.

I hope that you enjoyed this tour of the clipboard. All basic aspects of the clipboard have been covered, and you should now have enough information to use the clipboard in your applications.



 
 

avtor: Klemen Šavli