Transferring Text Through the Clipboard

by John Zukowski

When you work with the Java Foundation Classes/Swing (JFC/Swing) text components, the cut, copy, and paste operations are automatically handled for you with the help of the EditorKit. Normally, you do not have to worry about creating code to access the clipboard. Instead, you ask the EditorKit for its support. To demonstrate text transfer capabilities, you'll create a program that manually copies and pastes with a JTextArea and then changes that program to use EditorKit.

Given a JTextArea (or any JTextComponent), the code to do a copy operation involves getting the selected text from the component and placing it on the clipboard:
   String selection = jt.getSelectedText();
   StringSelection data = new StringSelection(selection);
   Clipboard clipboard = 
        Toolkit.getDefaultToolkit().getSystemClipboard();
   clipboard.setContents(data, data);
The related classes here, StringSelection and Clipboard, are found in the java.awt.datatransfer package.

Code to do the pasting operation is a little more involved, due to the necessary exceptions you need to handle. First, you get a Transferable object from the clipboard; then, you have fun with flavors. A DataFlavor is a format for transferring data across the clipboard. If, for instance, the current data on the clipboard is an image, you won't be able to paste it into a JTextArea as a string. Provided the format is correct, you get the data and put it into the text component.
   Transferable clipData = clipboard.getContents(clipboard);
   if (clipData != null) {
     try {
       if (clipData.isDataFlavorSupported(DataFlavor.stringFlavor)) {
         String s = (String)(clipData.getTransferData(
           DataFlavor.stringFlavor));
         jt.replaceSelection(s);
       }
     } catch (UnsupportedFlavorException ufe) {
       System.err.println("Flavor unsupported: " + ufe);
     } catch (IOException ioe) {
       System.err.println("Data not available: " + ioe);
     }
   }
Putting all this together gives you the following program:
import java.awt.\*;
import java.awt.event.\*;
import java.awt.datatransfer.\*;
import javax.swing.\*;
import java.io.\*;

public class Clip {
  public static void main(String args[]) {

    Runnable runner = new Runnable() {
      public void run() {
        JFrame frame = new JFrame("Clip");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final Clipboard clipboard =
          frame.getToolkit().getSystemClipboard();

        final JTextArea jt = new JTextArea();

        JScrollPane pane = new JScrollPane(jt);
        frame.add(pane, BorderLayout.CENTER);

        JButton copy = new JButton("Copy");
        copy.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            String selection = jt.getSelectedText();
            StringSelection data = new StringSelection(selection);
            clipboard.setContents(data, data);
          }
        });

        JButton paste = new JButton("Paste");
        paste.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent actionEvent) {
            Transferable clipData = clipboard.getContents(clipboard);
            if (clipData != null) {
              try {
                if 
                  (clipData.isDataFlavorSupported
				    (DataFlavor.stringFlavor)) {
                      String s = (String)(clipData.getTransferData(
                        DataFlavor.stringFlavor));
                  jt.replaceSelection(s);
                }
              } catch (UnsupportedFlavorException ufe) {
                System.err.println("Flavor unsupported: " + ufe);
              } catch (IOException ioe) {
                System.err.println("Data not available: " + ioe);
              }
            }
          }
        });
        JPanel p = new JPanel();
        p.add(copy);
        p.add(paste);
        frame.add(p, BorderLayout.SOUTH);
        frame.setSize(300, 300);
        frame.setVisible(true);
      }
    };
    EventQueue.invokeLater(runner);
  }
}

You should see an application similar to the image below:

Copy and Paste

Although the work in this program demonstrates how to transfer text through the clipboard, the custom ActionListener implementations were unnecessary. You can swap out the two new ActionListener() calls with something much simpler. Each Swing text component uses an EditorKit to define the set of actions that can be done with the component. By default, the kit used is the DefaultEditorKit, which defines behaviors for copy-and-paste support, as well as cursor movement and many others.

Behaviors like copy and paste are special Action objects called TextAction. They work by automatically finding the last focused text component and performing the designated action against them.

To use the actions associated with a text component, you get the list of actions from the text component and find the specific one you are looking for based on keys provided by the EditorKit. This gives you an ActionListener that you can associate with the JButton component in this case or with a JMenuItem if there are menus. When the component is activated, the action is then automatically done against the last focused text component.

To replace the action handlers in the previous example with the built-in handlers, you would use the following code to get the specific ActionListener objects. Basically, you first create a table of all the handlers and then look for the specific two of interest.
   import javax.swing.text.\*;
   ...
   // get command table
   ActionMap actionMap = jt.getActionMap();
   // Find specific commands
   Action copyAction = actionMap.get(DefaultEditorKit.copyAction);
   Action pasteAction = actionMap.get(DefaultEditorKit.pasteAction);
Once you have the handlers, you just attach them to the buttons, and you're done. You don't have to programmatically access the clipboard at all.
   copy.addActionListener(copyAction);
   paste.addActionListener(pasteAction);
Functionally, the two programs are identical. With the changes, the second version takes advantage of the code already written to do operations on text components. Be sure to see the DefaultEditorKit class for a list of all the different predefined operations you can perform.

Comments:

nice code

Posted by Anand on September 26, 2007 at 02:30 PM PDT #

you don't have a cut action...

Posted by cerebus on February 27, 2009 at 05:11 PM PST #

Post a Comment:
Comments are closed for this entry.
About

Java Technology Fundamentals are now covered as part of the Core Java Technology Tech Tips. Please go there for more tech tips.

Search

Archives
« April 2015
SunMonTueWedThuFriSat
   
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
  
       
Today