Drag and drop is a capability that allows users to perform operations on objects by dragging files' GUI components to the GUI components of objects that represent the operations. Most windowing systems provide desktops that display icons representing programs, files, printers, and storage devices. You drag a file's icon to a program icon to have the file opened by the program, to a printer icon to send the file to the printer, or to a storage device to have the file copied to that device.
Drag-and-drop capabilities are introduced to the Core API with JDK 1.2. These capabilities allow you to use drag and drop within Java applications, between Java applications, and between Java applications and native applications. This chapter shows you how to use drag and drop in your Java programs. It covers the basic mechanics of drag and drop, describes the Drag and Drop API, and provides examples of Java programs that implement drag and drop. When you finish this chapter, you'll be able to use drag and drop in your Java applications.
Drag and drop consists of the following three levels of abstraction:
Drag and drop is implemented using special objects, referred to as the drag source and drop target (see Figure 16.1). A GUI component that receives drops is associated with a drop target object that is activated and waits for drop events. The GUI creates the drag source at the beginning of the drag gesture. The drag source monitors the progress of the drag operation by handling events from the GUI. When the drag-and-drop operation is completed (the user drops the source component on the target component), the drop target coordinates with the drag source to transfer information from the source component to the target component. If the source and target components are associated with other objects (such as files or devices), these components effect data transfers between these other objects.
The Drag and Drop API consists of the java.awt.dnd package. However, it is implemented using other packages, most notably the java.awt.datatransfer package. The java.awt.dnd package consists of 4 interfaces and 15 classes. These interfaces and classes are summarized as follows:
FIGURE 16.1. How drag and drop works.
Drag and drop is implemented by setting up DragSource and DropTarget objects for those GUI components that you want to use as a source or destination of drag-and-drop operations. You can implement only sources, only targets, or both sources and targets, depending on the requirements of your application. A DragSource object is associated with a GUI component from which you want to have data transferred, and a DropTarget component is associated with a GUI component that is to receive transferred data. Once these components are set up, the bulk of the drag-and-drop processing consists of handling events associated with the sources and targets.
A DragSource object is associated with a GUI component by specifying the component as an argument to the object's start() method. A DropTarget object is associated with a GUI component by passing the component as an argument to the object's constructor. Information is transferred from the source component to the target component via an object of the Transferable interface. You declare a class that implements this interface to effect the data transfer. The example in the following section illustrates the use of the DragSource, DropTarget, and Transferable objects.
Now that you've been introduced to the Drag and Drop API, we'll create an example application that implements both the source and target aspects of drag and drop. Listing 16.1 presents the DragNDrop application. This program displays the opening window, shown in Figure 16.2. Its GUI uses two text boxes to implement drag and drop. Type some text in the upper text box and then drag the text to the lower text box, as shown in Figure 16.3. Note how the cursor changes shape during the drag-and-drop operation. The program also displays text to the console window that identifies the drag-and-drop events that are handled.
FIGURE 16.2. The DragNDrop application opening window.
FIGURE 16.3. Dragging text from one text area to another.
The DragNDrop application illustrates both source and target event-handling in support of drag and drop. The program declares the needed GUI components and then declares variables that are used to implement drag and drop. The source variable is assigned an object of the DragSource class, and the target variable is assigned an object of the DropTarget class. The DropTarget()constructor takes the following four arguments:
The transferable variable is assigned an object of the TextTransfer class, which is an inner class that implements the Transferable interface of java.awt.datatransfer.
The sourceHandler variable is assigned a DragSourceHandler object that is used to handle source-related events.
The setup() method sets the DropTarget object referenced by target to actively receive drops via the setActive()method. A DragGestureRecognizer is created with respect to the first TextArea object so that drag opertations can be detected and processed. The rest of the program (with the exception of TextTransfer) consists of event handlers.
The DragSourceHandler class implements the DragSourceListener interface to handle source-related events. The dropActionChanged(), dragEnter(), and dragDropEnd() methods just display notices about the occurrence of events. The dragOver() method doesn't display anything because it may be invoked many times during a drag-and-drop operation.
The DropTargetHandler class implements the DropTargetListener interface to handle target-related events. The dragEnter() method handles the event that occurs when a drag operation enters the component (the second TextArea object) associated with the DropTarget. This method checks if the data flavors of the object being dragged to the target support any of the standard text data flavors. If so, the drag is accepted. Other-wise, it is rejected. The dragOver(), dragExit(), and dropAction() methods are placeholders used to implement the DropTargetListener interface.
The drop() method implements the actual data transfer. It accepts the drop action and gets a Transferable object that contains the data being transferred. It retrieves the data flavors associated with the Transferable object and checks to see whether these flavors coincide with the target's flavors. If a match occurs, the associated TextArea object is updated with the transferred data. The successful completion of the drop is signaled by the dropComplete() method of the DropTargetContext class.
The TextTransfer class implements the Transferable interface and is used to transfer information from the DragSource object. The getTransferDataFlavors() method returns the flavors supported by the source. The isDataFlavorSupported() method reports information on a single data flavor. The getTransferData() method returns the data to be transferred.
The DragHandler class implements DragGestureListener to start the drag operation when a drag operation is initiated in the first text area. It handles this event by invoking the event's startDrag() method. This method takes the following arguments:
The WindowEventHandler class handles the closing of the application window.
import java.awt.*; import java.awt.event.*; import java.awt.dnd.*; import java.awt.datatransfer.*; import java.io.*; public class DragNDrop extends Frame { int screenWidth = 400; int screenHeight = 400; Panel panel = new Panel(); Label topLabel = new Label("Enter text in this text area:"); Label bottomLabel = new Label("And then drag it to this text area:"); TextArea textArea1 = new TextArea(); TextArea textArea2 = new TextArea(); //Drag and drop variables DragSource source = new DragSource(); DropTarget target = new DropTarget(textArea2, DnDConstants.ACTION_COPY,new DropTargetHandler(),true); TextTransfer transferable = new TextTransfer(); DragSourceHandler sourceHandler = new DragSourceHandler(); public static void main(String[] args) { DragNDrop app = new DragNDrop(); } public DragNDrop() { super("DragNDrop"); setup(); setSize(screenWidth,screenHeight); addWindowListener(new WindowEventHandler()); show(); } void setup() { target.setActive(true); panel.setLayout(new GridLayout(4,1)); panel.add(topLabel); panel.add(textArea1); Toolkit toolkit=Toolkit.getDefaultToolkit(); try{ toolkit.createDragGestureRecognizer(Class.forName( "java.awt.dnd.MouseDragGestureRecognizer"),source,textArea1, DnDConstants.ACTION COPY,new DragHandler()); }catch(ClassNotFoundException ex){ System.out.println("Recognizer class not found."); System.exit(o); } panel.add(bottomLabel); panel.add(textArea2); add("Center",panel); } class DragSourceHandler implements DragSourceListener { public void dropActionChanged(DragSourceDragEvent ev) { System.out.println("Source: Drop action changed"); } public void dragEnter(DragSourceDragEvent ev) { System.out.println("Source: Drag enter"); } public void dragOver(DragSourceDragEvent ev) { } public void dragExit(DragSourceEvent ev) { System.out.println("Source: Drag exit"); } public void dragDropEnd(DragSourceDropEvent ev) { System.out.println("Source: Drag drop end"); } } class DropTargetHandler implements DropTargetListener { public void dragEnter(DropTargetDragEvent ev) { System.out.println ("Target: Drag enter"); DataFlavor df[] = ev.getCurrentDataFlavors(); for (int i = 0; i < df.length; i++) { if (df[i].equals (DataFlavor.plainTextFlavor) || df[i].equals (DataFlavor.stringFlavor)) { ev.acceptDrag(DnDConstants.ACTION_COPY); return; } } ev.rejectDrag(); } public void dragOver(DropTargetDragEvent ev) { } public void dragExit(DropTargetEvent ev) { System.out.println ("Target: Drag exit"); } public void dropActionChanged(DropTargetDragEvent ev) { System.out.println("Target: Drop action changed"); } public void drop(DropTargetDropEvent ev) { System.out.println ("Target: Dropped"); ev.acceptDrop (DnDConstants.ACTION_COPY); Transferable transfer = ev.getTransferable(); DataFlavor df[] = ev.getCurrentDataFlavors(); String input = ""; try { for (int i=0;i<df.length;i++) { if (df[i].equals(DataFlavor.stringFlavor) || df[i].equals(DataFlavor.plainTextFlavor)) { input = (String) transfer.getTransferData(df[i]); } } textArea2.setText(input); }catch (Exception e) { System.out.println(e.toString()); } try { target.getDropTargetContext().dropComplete(true); }catch (Exception e) { } } } class TextTransfer implements Transferable { public DataFlavor[] getTransferDataFlavors() { DataFlavor[] flavors = new DataFlavor[1]; flavors[0] = DataFlavor.plainTextFlavor; return flavors; } public boolean isDataFlavorSupported(DataFlavor flavor) { return (flavor.equals(DataFlavor.plainTextFlavor)); } public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { return textArea1.getText(); } } class DragHandler implements DragGestureListener { public void dragGestureRecognized(DragGestureEvent e) { e.startDrag (new Cursor(Cursor.HANDCURSOR), transferable,sourceHandler); } } class WindowEventHandler extends WindowAdapter { public void windowClosing(WindowEvent e){ System.exit(0); } } }
This chapter showed you how to use the drag-and-drop capabilities of JDK 1.2. It covered the basic mechanics of drag and drop, described the Drag and Drop API, and provided examples of Java programs that implement drag and drop. In the next chapter you'll learn how to use the sophisticated input/output capabilities of the java.io package.
© Copyright, Macmillan Computer Publishing. All rights reserved.