Example 6-3 shows the ColorSink class, which is a simple subclass of the Swing JTextArea class. ColorSink allows color objects to be pasted or dropped on it. When either event occurs, ColorSink sets its background color to the transferred color object. In addition, the class allows the pasting of textual data, which it inserts at the current cursor position. Finally, ColorSink accepts drops of the DataFlavor.javaFileListFlavor type. This data flavor is used when the user drags and drops a file icon. When a ColorSink receives a drop of this type, it opens the specified file (which it assumes to be a text file) and reads and displays its contents.
The pastecolor() method does the work of transferring a color through cut-and-paste. Again, for simplicity, the pastecolor() method is invoked when the user double-clicks on the ColorSink. The drag-and-drop transfer is implemented primarily in the drop() method. Note, however, that dragEnter() and dragExit() perform a simple drag-under effect by highlighting the ColorSink border.
The ColorSink class also includes a simple main() method that shows how it can be combined with the ColorSource class to create a simple demonstration of cut-and-paste and drag-and-drop.
import java.awt.*; import java.awt.event.*; import java.awt.datatransfer.*; import java.awt.dnd.*; import javax.swing.*; import javax.swing.border.*; import java.io.*; import java.util.List; /** * This simple JTextArea subclass allows TransferableColor objects to * be pasted or dropped into it. It also supports the pasting of * text and the dropping of File objects. */ public class ColorSink extends JTextArea implements DropTargetListener { /** Create a new ColorSink object */ public ColorSink() { // Listen for double-clicks. Use them to trigger a paste action. addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { pastecolor(); e.consume(); } } }); // We have to create a DropTarget object to support drag-and-drop. // It will listen for drops on top of us and notify our DropTargetListener // methods when drag-and-drop-related events occur. setDropTarget(new DropTarget(this, this)); } // This method is invoked when the user double-clicks on us. It attempts // to paste a color or text. Note that the JTextArea we extend // already supports cut-and-paste of text through the Ctrl-V keystroke. // This adds a different kind of cut-and-paste for demonstration purposes. public void pastecolor() { // Get the clipboard, and read its contents Clipboard c = this.getToolkit().getSystemClipboard(); Transferable t = c.getContents(this); if (t == null) { // If nothing to paste this.getToolkit().beep(); // then beep and do nothing return; } try { // If the clipboard contained a color, use it as the background color if (t.isDataFlavorSupported(TransferableColor.colorFlavor)) { Color color = (Color) t.getTransferData(TransferableColor.colorFlavor); this.setBackground(color); } // If the clipboard contained text, insert it. else if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) { String s = (String) t.getTransferData(DataFlavor.stringFlavor); this.replaceSelection(s); } // Otherwise, we don't know how to paste the data, so just beep else this.getToolkit().beep(); } catch (UnsupportedFlavorException ex) { this.getToolkit().beep(); } catch (IOException ex) { this.getToolkit().beep(); } } // The methods below are the methods of DropTargetListener. // They are invoked at various times when something is being // dragged over us, and allow us an opportunity to respond to the drag. // This is the border we display when the user is dragging over us. protected static Border dropBorder = new BevelBorder(BevelBorder.LOWERED); // Something is being dragged over us. If we can support this data type. // tell the drag-and-drop system that we are interested, and display // a special border to tell the user that we're interested. public void dragEnter(DropTargetDragEvent e) { if (e.isDataFlavorSupported(TransferableColor.colorFlavor) || e.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE); this.setBorder(dropBorder); } } /** The user is no longer dragging over us, so restore the default border */ public void dragExit(DropTargetEvent e) { this.setBorder(null); } /** This method is invoked when the user drops something on us */ public void drop(DropTargetDropEvent e){ this.setBorder(null); // Restore the default border Transferable t = e.getTransferable(); // Get the data that was dropped // Check for types of data that we support if (t.isDataFlavorSupported(TransferableColor.colorFlavor)) { // If it was a color, accept it, and use it as the background color e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); try { Color c = (Color) t.getTransferData(TransferableColor.colorFlavor); this.setBackground(c); e.dropComplete(true); } catch (Exception ex) { e.dropComplete(false); } } else if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { // If it was a file list, accept it, read the first file in the list // and display the file contents e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); try { List files = (List) t.getTransferData(DataFlavor.javaFileListFlavor); File f = (File) files.get(0); BufferedReader in = new BufferedReader(new FileReader(f)); String s; this.setText(""); while((s = in.readLine()) != null) this.append(s); e.dropComplete(true); } catch (Exception ex) { e.dropComplete(false); } } else { // If it wasn't a color or a file list, reject it e.rejectDrop(); return; } } // These are unused DropTargetListener methods public void dragOver(DropTargetDragEvent e) {} public void dropActionChanged(DropTargetDragEvent e) {} /** This is a simple test program for ColorSource and ColorSink */ public static void main(String[] args) { // Create a window JFrame f = new JFrame("ColorSourceTest"); f.getContentPane().setLayout(new BorderLayout()); // Add some ColorSources JPanel panel = new JPanel(); f.getContentPane().add(panel, BorderLayout.NORTH); panel.add(new ColorSource(Color.yellow)); panel.add(new ColorSource(Color.pink)); panel.add(new ColorSource(Color.white)); panel.add(new ColorSource(Color.gray)); // Add a ColorSink ColorSink sink = new ColorSink(); f.getContentPane().add(sink, BorderLayout.CENTER); // Pop it all up f.setSize(400, 300); f.show(); } }
Copyright © 2001 O'Reilly & Associates. All rights reserved.