Use Java to Interact with Your Clipboard

clipboard acts as a temporary staging area where application users store cut or copied information, including text, graphics, objects, and other data types. It is a heavily exploited data sharing facility. Therefore, when developing new applications, it makes sense to expend extra effort to support the clipboard. Neglecting clipboard functionality can result in an application that gets complaints, requires new development, or?worst of all?never gets used.

But how does one go about writing to and reading from the clipboard using Java? Sun Microsystems provides the java.awt.datatransfer package as part of the Java framework, which allows you to support the clipboard. In this article, you’ll learn how to copy/cut and paste both text and images using java.awt.datatransfer.

The Data Transfer Framework
The framework that makes cutting/copying/pasting possible in Java was introduced in Java 1.1 with the java.awt.datatransfer package. Core to the data transfer framework are the java.awt.datatransfer.DataFlavor class and the java.awt.datatransfer.Transferable interface.

The DataFlavor Class
The java.awt.datatransfer.DataFlavor class describes the data types and data formats you’ll be transferring on the clipboard. The clipboard can be used to stage a variety of types of data, like text, graphics, and sound files. Because of this, you need a way to describe what type of data is being written to/read from the clipboard. Think of the DataFlavor object as the holder of metadata which defines the clipboard item. Describe the data type defined by DataFlavor using a MIME type. This is exemplified in the syntax below, which creates a new DataFlavor object named jpegFlavor. The first argument of the constructor is the MIME type (“image/jpeg”) and the second argument is a human-readable name for the data type (“JPEG image”).

DataFlavor jpegFlavor = new DataFlavor("image/jpeg","JPEG image");

In cases where you’re planning to pass clipboard data between different JVMs, you can also define a DataFlavor using a class definition. When you put Java objects on the clipboard, object serialization is used behind the scenes to transfer a given object from one JVM to another. The code below shows how to create a Flavor object for the java.awt.Polygon class. Again, the second argument represents the human readable form you want associated to the Flavor. The first constructor argument represents the class name of the object for which you’re defining the Flavor object:

DataFlavor polygonFlavor = new DataFlavor(java.awt.Polygon.class,"Java Polygon Object");

The Transferable Interface
While the DataTransfer class defined the type of the data you’re placing on the clipboard, you still need an object type to transfer the data payload. To do this, put the data in an object that implements the java.awt.datatransfer.Transferable interface.

When you transfer a clipboard item from one application to another, the application to which you are pasting might not understand the source data in its proprietary format. For example, when you copy Microsoft Word text, it will contain certain information with it about text formatting. When you paste this clipboard item to Notepad, the item is copied, stripping all the formatting from the original clipboard item.

To replicate this in the Java world, you can have the object that you place on the clipboard support multiple MIME types. In the example above, you could support the MIME type of “application/msword” (representing Microsoft Word) as well as the MIME type of “text/plain” (representing plain text).

The Transferable interface requires upi to implement three methods:

  • DataFlavor[] getDataTransferDataFlavors(): This method returns an array of DataFlavor objects. It tells you what Flavor types are supported by a given Transferable implementation.
  • public boolean isDataFlavorSupported(DataFlavor flavor): This method takes in a given DataFlavor and tells you if it is supported by the given Transferable implementation
  • public Object getTransferData(DataFlavor flavor): this method takes in a given DataFlavor and returns an Object that contains the payload of the clipboard item. The object is returned either as a serialized Java Object or a java.io.InputStream object, depending on the type of DataFlavor that was passed in. This method can throw a java.awt.datatransfer.UnspportedFlavorException if the requested DataFlavor does not fall in the list of DataFlavors for which you have claimed support.

Local & System Clipboards
Java has two different types of clipboards: local and system. Local clipboards are available only within the Java Virtual Machine (JVM). You can also have multiple local clipboards. Unfortunately, with local clipboards, you can’t interact with the clipboard of your operating system. The System clipboard provides you this facility.

Use the following syntax to get a reference to the system clipboard (represented by a Clipboard object):

Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); 

To create a local clipboard, use the Clipboard constructor, which takes in a name for your clipboard:

Clipboard localClipboard = new Clipboard("My local clipboard");

Let’s See Some Code!
This text-based example grabs text from the clipboard and then writes to it.

The downloadable sample code provided with this article contains the class TextGrabber, which is shown below. Test the code out by opening up Notepad. Type a small text message and copy the message to your clipboard using Ctrl-C as you normally would copy text. When you execute the class, you should see that the class echoes what you placed on the clipboard.

public class TextGrabber {	public static String getClipboard() {		// get the system clipboard		Clipboard systemClipboard =			Toolkit				.getDefaultToolkit()				.getSystemClipboard();		// get the contents on the clipboard in a 		// transferable object		Transferable clipboardContents =			systemClipboard				.getContents(				null);		// check if clipboard is empty		if (clipboardContents			== null) {			return ("Clipboard is empty!!!");		} else			try {				// see if DataFlavor of 				// DataFlavor.stringFlavor is supported				if (clipboardContents					.isDataFlavorSupported(						DataFlavor							.stringFlavor)) {					// return text content					String returnText =						(							String) clipboardContents								.getTransferData(							DataFlavor								.stringFlavor);					return returnText;				}			} catch (UnsupportedFlavorException ufe) {				ufe.printStackTrace();			} catch (IOException ioe) {				ioe.printStackTrace();			}		return null;	}	public static void main(String[] args) {		System.out.println(			"Copying text from system clipboard.");		String grabbed = getClipboard();		System.out.println(grabbed);	}}

In the code above, the system clipboard is a Clipboard object, which then uses the getContents method of the object to return the contents of the clipboard as a Transferable object. From there, make sure to support the predefined flavor of DataFlavor.stringFlavor (a Flavor innate in the DataFlavor object, which represents a Java Unicode String class). After confirming support for DataFlavor.stringFlavor, use the getTransferData method of the clipboard object, passing to it the argument of the DataFlavor.stringFlavor DataFlavor. This yields the clipboard text which returns as a String to the calling method.

Writing to Text to the Clipboard
The class TextWriter (contained in the sample code) shown below demonstrates how to write text to the clipboard:

public class TextWriter {	public static void writeToClipboard(String writeMe) {		// get the system clipboard		Clipboard systemClipboard =			Toolkit				.getDefaultToolkit()				.getSystemClipboard();		// set the textual content on the clipboard to our 		// Transferable object		// we use the 		Transferable transferableText =			new StringSelection(writeMe);		systemClipboard.setContents(			transferableText,			null);	}	public static void main(String[] args) {		System.out.println(			"Writing text to the system clipboard.");		String writeMe =			"I'd like to be put on the clipboard";		writeToClipboard(writeMe);	}}

Get the system Clipboard object and write to it using the setContents method. This method requires you to provide the payload of what you want to write as a Transferable object. Since you aren’t allowed to instantiate the interface, use the StringSelection implementation which implements the Transferable interface.

Figure 1. Testing Proper Function Execution: Use Notepad to ensure the TextWriter program properly wrote text to the system clipboard.

After executing the TextWriter class, you can execute the TextGrabber class to make sure text was written to the Clipboard. For a more convincing test of proper function execution, open up Notepad and use the Paste (Ctrl+V) function to make sure the text found its way to its clipboard destination. Figure 1 demonstrates:

What About Images and the Clipboard?
Java 1.4 also introduced the java.awt.datatransfer.DataFlavor.imageFlavor predefined Flavor. As with java.awt.datatransfer.DataFlavor.stringFlavor, having a Flavor predefined makes life pretty straightforward. imageFlavor represents the Java Image class: java.awt.Image. The MIME type associated with this flavor is “image/x-java-image.” The imageFlavor Flavor allows you to interact with common image formats like GIF and JPEG on the clipboard.

The sample code [link] for this article provides a class named Viewer. This class simply takes a java.awt.Image object and draws the image to the screen. The code for the Viewer class is shown below, as you can see, there is nothing really out of the ordinary with the java.awt code. I do use a MediaTracker to make sure my image is loaded before attempting to display it.

import java.awt.Frame;import java.awt.Graphics;import java.awt.Image;import java.awt.MediaTracker;import java.awt.Toolkit;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;public class Viewer extends Frame {  private Image image;  // method takes in a java.awt.Image object   // and displays it  public Viewer(Image viewMe)   {    image = viewMe;    // use a MediaTracker to make sure object    // is loaded before trying to display it    MediaTracker mediaTracker = new MediaTracker(this);    mediaTracker.addImage(image, 0);    try    {      mediaTracker.waitForID(0);    }    catch (InterruptedException ie)    {      System.err.println(ie);      System.exit(1);    }    System.out.println("Finished loading image object");    // add a Window Listener to handle closing of a window    addWindowListener(new WindowAdapter()     {      public void windowClosing(WindowEvent e)       {        System.exit(0);      }    });    // set size of display window    setSize(image.getWidth(null), image.getHeight(null));    // set title of display window    setTitle("Viewing Image from Clipboard");    // show image    show();  }  public void paint(Graphics graphics)   {    graphics.drawImage(image, 0,0, null);  }}

Grabbing an Image from the Clipboard
The ImageGrabber class in the sample code shows how to grab an image from the system clipboard and then display it using the Viewer class. The method getImageFromClipboard takes on the bulk of the work by grabbing the clipboard contents. The clipboard contents are grabbed from the system Clipboard object and stored in a Transferable object the same way that was done with the TextGrabber class. If it turns out that the clipboard contents are something that fall under the umbrella of image formats supported by the imageFlavor Flavor, then you go ahead and caste your Transferable object to an Image object.

    public static Image getImageFromClipboard() {    // get the system clipboard  Clipboard systemClipboard =    Toolkit    .getDefaultToolkit()    .getSystemClipboard();    // get the contents on the clipboard in a   // Transferable object  Transferable clipboardContents =    systemClipboard    .getContents(null);    // check if contents are empty, if so, return null  if (clipboardContents == null)    return null;  else  try {    // make sure content on clipboard is     // falls under a format supported by the     // imageFlavor Flavor    if (clipboardContents        .isDataFlavorSupported(        DataFlavor.imageFlavor))        {         // convert the Transferable object         // to an Image object         Image image =           (Image) clipboardContents                   .getTransferData(DataFlavor.imageFlavor);         return image;       }      } catch (UnsupportedFlavorException ufe) {        ufe.printStackTrace();      } catch (IOException ioe) {        ioe.printStackTrace();      }      return null;   }

The ImageGrabber class’ main method passes the Image object retrieved from the system clipboard on to the Viewer class for displaying to the user.

To test the ImageGrabber class out, you can go to your favorite image viewing software and copy a GIF or JPEG image to the clipboard. Then execute the ImageGrabber class. If things are working correctly, you should see the image displayed.Copying an Image to the Clipboard
This process is exemplified in the class ImageWriter. The ImageWriter class reads in an image file from disk and copies it to the clipboard. The interesting work of this class is performed by a couple of static methods and an inner class.

The static method grabImageFromFile does what its name implies?it takes in a file name and returns an Image:

  public static Image grabImageFromFile(String fileName) {    Toolkit toolkit =      Toolkit.getDefaultToolkit();    Image image =      toolkit.getImage(fileName);    System.out.println("Done loading");    return image;  }

The filename is received from standard input in the main method of the ImageWriter class; the sample code allows you to type in the location of the image file you would like to copy to the clipboard. Remember to use \ instead of , as the program expects a Java-friendly file path.

The next major method of the ImageGrabber class is the static method setClipboard:

  public static void setClipboard(Image image) {    ImageSelection imageSelection =      new ImageSelection(image);    Toolkit      .getDefaultToolkit()      .getSystemClipboard()      .setContents(imageSelection, null);  }

The above method simply takes an java.awt.Image object and copies it to the system clipboard. This is done via the setContents method of the Clipboard object representing the system clipboard. The setContents method expects a Transferable object as its first argument to transfer the data payload. The code uses an ImageSelection as the argument. But what is this ImageSelection object?

I created the ImageSelection class myself as an inner class:

  // Inner class is used to hold an image while on the clipboard.  public static class ImageSelection    implements Transferable   {    // the Image object which will be housed by the ImageSelection    private Image image;    public ImageSelection(Image image) {      this.image = image;    }    // Returns the supported flavors of our implementation    public DataFlavor[] getTransferDataFlavors()     {      return new DataFlavor[] {DataFlavor.imageFlavor};    }        // Returns true if flavor is supported    public boolean isDataFlavorSupported(DataFlavor flavor)     {      return DataFlavor.imageFlavor.equals(flavor);    }    // Returns Image object housed by Transferable object    public Object getTransferData(DataFlavor flavor)      throws UnsupportedFlavorException,IOException     {      if (!DataFlavor.imageFlavor.equals(flavor))       {        throw new UnsupportedFlavorException(flavor);      }      // else return the payload      return image;    }  }

Earlier in this article, I discussed the Transferable interface. When dealing with text, you were spoon-fed with the java.awt.datatransfer.StringSelection implementation of the java.awt.datatransfer.Transferable interface. With images, the Java language does not provide an innate Transferable implementation that supports images. Thus, you need to create one. As stated earlier, to implement the Transferable interface, you are mandated to implement the getDataTransferDataFlavors() method to return an array of DataFlavor types you support. In this case, I returned an array of size one which simply included the DataFlavor.imageFlavor Flavor. Next, defined the method: DataFlavor object is supported by the Transferable implementation. I am only interested in incoming arguments of the imageFlavor Flavor, so that’s the only time I’ll return true. Lastly, I implemented the getTransferData method. It is here that if the incoming DataFlavor is, in fact, the imageFlavor Flavor, I return the private java.awt.Image object (i.e., my payload) housed in the Transferable object.

To test the ImageGrabber class, execute the class and you will be prompted to provide the path to an image file. Go ahead and provide the DOS file location to a GIF or JPEG file. After execution, if things have gone according to plan, you should be able to open up your favorite image editing program and see that the image you specified is available for pasting (i.e., it was added to the keyboardclipboard). You can also use the ImageGrabber class introduced earlier prove to yourself that the image you pointed to was written to the clipboard.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: