24.1 What Is Drag and Drop?


If you have ever used a graphical file system manager to move a file from one folder to another, you have used Drag and Drop (often abbreviated DnD). The term "drag and drop" refers to a GUI action in which the end user "picks up" an object such as a file or piece of text by moving the cursor over the object, clicking the mouse button, and, without releasing the button, "dragging" the object to a particular area of the screen and releasing the mouse button to "drop" the object. This process is meant to extend the desktop metaphor. Just like your real desktop, you can rearrange things by picking them up, moving them, and dropping them in a filing cabinet, a trash can, an in-box, a shoebox, or the floor.

Some programmers have added DnD functionality to individual components. For example, you might want to have a graphically rearrangeable JTree. Even without the DnD package, you can accomplish this with a clever bit of programming and a good deal of time. With the DnD package, however, not only do you not need the clever bit of programming, you are not limited to one component. You can drag information from one component to another in the same application, in two different Java applications (using separate JVMs), or even between your Java application and the native windowing system.

24.1.1 DnD and SDK 1.4

SDK 1.4 introduced several new features that make minimal DnD functionality easy to program for simple cases. On the drag side, many components now have a new boolean property called dragEnabled. If you set this property to true, you can "export" information by dragging it away from the component. Table 24-1 shows the Swing components that support the dragEnabled property and the format of the information they export.

Table 24-1. Export capabilities of various Swing components

Component

Export data type(s)

Description

JColorChooser

application/x-java-jvm-local-objectref

Exports a reference to a java.awt.Color object. Imports a color TransferHandler property so you can accept such a drag.

JEditorPane

text/plain, other

If the content type for the editor is not plain text, the export contains both a plain-text version and an "other" version determined by the write( ) method of the editor pane.

JFileChooser

application/x-java-file-list

The files dragged out of a JFileChooser are set up in the same manner as those of a native file chooser. If you drop them on a Java drop site, the type is x-java-file-list.

JFormattedTextField

text/plain

Recall that the "format" in this text field refers to text validation, not visual formatting such as that found in HTML.

JList

text/plain

text/html

Single items drag out as plain text. Multiple items generate a chunk of HTML representing an unordered list. Each item is one entry in the list.

JTable

text/plain

text/html

Single cells drag out as plain text. Multiple cells generate a chunk of HTML representing a table bounding the cells.

JTextArea

text/plain

Any text dragged out is presented as plain text.

JTextField

text/plain

Any text dragged out is presented as plain text.

JTextPane

text/plain, other

If the content type for the text pane is not plain text, the export contains both a plain-text version and an "other" version determined by the write( ) method of the pane.

JTree

text/plain

text/html

Single items drag out as plain text. Multiple items generate a chunk of HTML representing an unordered list. Each item is one entry in the list. The hierarchy of disparate tree nodes is not maintained (i.e., the exported HTML does not contain nested lists).

On the drop side, the text components all support basic drop functionality. Other components (JList, JTable, etc.) have a new property called transferHandler. If you set the transferHandler, you can easily accept dropped data of almost any type. Table 24-2 shows a list of the default import capabilities of several Swing components.

Table 24-2. Import capabilities of several Swing components

Component

Import data type(s)

Description

JColorChooser

class=java.awt.Color

Any transfer with a representation class (or subclass) of Color is accepted.

JEditorPane

text/plain, other

Accepts incoming plain text as well as text with the same MIME type as the current document. (The read( ) method of the pane is used.)

JFormattedTextField

text/plain

Plain text is effectively typed into the field to maintain format validation.

JPasswordField

text/plain

Text can be inserted, but it is shown as stars or whatever the current echo character is set to display.

JTextArea

text/plain

Plain text is inserted at the current caret position.

JTextField

text/plain

Plain text is inserted at the current caret position.

JTextPane

text/plain, other

Accepts incoming plain text as well as text with the same MIME type as the current document. (The read( ) method of the pane is used.)

To get you going with the new "easy" stuff, let's start with an example. To show you the results of a drop, Figure 24-1 shows a screenshot of an all-encompassing transfer handler attached to a text area. You can drag all kinds of information: icons from your desktop, text from an editor, a chunk of cells from a spreadsheet, several items from a JTree in another window just about anything. Drop your items in the text window, and it shows you the possible transfer flavors. If it knows how to handle any of the flavors (text, Java objects, etc.), it displays as much of the actual data as it can.

Figure 24-1. UberHandler demo with a drop from a Microsoft Excel® spreadsheet
figs/swng2.2401.gif

The source code for this handler follows. The (simple) GUI application you see in Figure 24-1 is built in the main( ) method of this handler. You could certainly ignore this application and attach the handler to a more elegant debugger of your own devising.

// UberHandler.java import javax.swing.*; import java.awt.event.*; import java.awt.dnd.*; import java.awt.datatransfer.*; import java.io.*; public class UberHandler extends TransferHandler {   JTextArea output;   public void TransferHandler( ) { }   public boolean canImport(JComponent dest, DataFlavor[] flavors) {     // You bet we can!     return true;   }   public boolean importData(JComponent src, Transferable transferable) {     // Here's the tricky part.     println("Receiving data from " + src);     println("Transferable object is: " + transferable);     println("Valid data flavors: ");     DataFlavor[] flavors = transferable.getTransferDataFlavors( );     DataFlavor listFlavor = null;     DataFlavor objectFlavor = null;     DataFlavor readerFlavor = null;     int lastFlavor = flavors.length - 1;     // Check the flavors and see if we find one we like. If we do, save it.     for (int f = 0; f <= lastFlavor; f++) {       println("  " + flavors[f]);       if (flavors[f].isFlavorJavaFileListType( )) {         listFlavor = flavors[f];       }       if (flavors[f].isFlavorSerializedObjectType( )) {         objectFlavor = flavors[f];       }       if (flavors[f].isRepresentationClassReader( )) {         readerFlavor = flavors[f];       }     }     // Now try to display the content of the drop.     try {       DataFlavor bestTextFlavor = DataFlavor.selectBestTextFlavor(flavors);       BufferedReader br = null;       String line = null;       if (bestTextFlavor != null) {         println("Best text flavor: " + bestTextFlavor.getMimeType( ));         println("Content:");         Reader r = bestTextFlavor.getReaderForText(transferable);         br = new BufferedReader(r);         line = br.readLine( );         while (line != null) {           println(line);           line = br.readLine( );         }         br.close( );       }       else if (listFlavor != null) {         java.util.List list =             (java.util.List)transferable.getTransferData(listFlavor);         println(list);       }       else if (objectFlavor != null) {         println("Data is a java object:\n" +                  transferable.getTransferData(objectFlavor));       }       else if (readerFlavor != null) {         println("Data is an InputStream:");         br = new BufferedReader((Reader)transferable.getTransferData(readerFlavor));         line = br.readLine( );         while (line != null) {           println(line);         }         br.close( );       }       else {         // Don't know this flavor type yet         println("No text representation to show.");       }       println("\n\n");     }     catch (Exception e) {       println("Caught exception decoding transfer:");       println(e);       return false;     }     return true;   }   public void exportDone(JComponent src, Transferable data, int action) {     // Just let us know when it occurs.     System.err.println("Export Done.");   }   public void setOutput(JTextArea jta) {     output = jta;   }   protected void print(Object o) {     print(o.toString( ));   }   protected void print(String s) {     if (output != null) {       output.append(s);     }     else {       System.out.println(s);     }   }   protected void println(Object o) {     println(o.toString( ));   }   protected void println(String s) {     if (output != null) {       output.append(s);       output.append("\n");     }     else {       System.out.println(s);     }   }   protected void println( ) {     println("");   }   public static void main(String args[]) {     JFrame frame = new JFrame("Debugging Drop Zone");     frame.setSize(500,300);     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     JTextArea jta = new JTextArea( );     frame.getContentPane( ).add(new JScrollPane(jta));     UberHandler uh = new UberHandler( );     uh.setOutput(jta);     jta.setTransferHandler(uh);     frame.setVisible(true);   } }

24.1.2 Programming with DnD

So how do we add more complex DnD functionality to a component? On the surface, it's very easy. DnD uses the same technique as most other GUI features: events. There are drag start events, drag source events, and drop events. To play with these events, implement the corresponding listener interfaces. Sound familiar? For example, to respond to a dropped object, we create an event handler that implements the DropTargetListener interface. What you do with the dropped object is the fun part.

Just to prove that this stuff really works, let's take a look at a simple example of the drop listener (Figure 24-2). This application shows the names of any files you drag from your native windowing system's file manager.

Figure 24-2. Two files dragged from a file manager onto our DropTest application
figs/swng2.2402.gif

Admittedly, a screenshot does not do this test program justice. You really should compile and run DropTest.java to get the full effect. But trust us, it does work! We'll look at the source code for this example later in this section. With SDK 1.4, things get significantly easier, but again, more of that to come. First let's look at an overview of what's involved.

You have three main areas to work with. A drop target accepts an incoming drag. The process of accepting the dragged information generates a series of events that you can respond to. The source of the dragged item might be your application, another Java application, or a native windowing system application such as your file manager. None of these matter to the drop target.

Your application can also be a source for draggable items. This functionality requires the other two parts of DnD: a drag recognizer and a drag source. The drag recognizer is really just a glorified event adapter that listens for events that indicate if a drag has begun. In the simplest cases, this is usually a mouseDragged( ) event from the MouseMotionListener interface. (Later in this chapter, you will see how to make other events trigger a drag.) Once a drag is recognized, the drag source starts a drag and properly wraps the dragged information in an object that a drop target can recognize. Like the drop target, the information in a drag source is used inside your own application, another Java application, or a native application. Of course, all of these examples need to know what to do with the information once it arrives, but there are no a priori restrictions on where you drop your data.

While you definitely should familiarize yourself with the DropTarget and DragSource classes, the driving force behind the DnD package is events. There are events for each of the three major players: drop target events, recognizer events, and drag source events. Use recognizer events to start the whole process. Your response to target and source events dictates the behavior of your application. Let's look at a typical series of events in DnD scenarios (see Table 24-3).

Table 24-3. Common DnD event methods

Event on system

Gesture recognizer methods

Drag source methods

Drop target methods

Click and drag an item such as a file.

dragGestureRecognized( )

   

Drag item into a possible drop area.

 

dragEnter( ) called first; dragOver( ) called continuously until exit

dragEnter( ) called first; dragOver( ) called continuously until exit

Drag item out of a possible drop area.

 

dragExit( )

dragExit( )

Drop the item on a target that accepts the drop.

 

dragExit( )dragDropEnd( )*

dragExit( )drop( )

Drop the item on a target that rejects the drop.

 

dragExit( )dragDropEnd( )*

dragExit( )drop( )

Drop the item on anything other than an active target.

 

dragExit( )dragDropEnd( )*

 

*You can determine the success status of a drop from the event passed to dragDropEnd( ).

Throughout the entire process, you can determine whether the user wants to copy or move the information based on keyboard modifiers such as the Control key. We'll describe the API for all of these events in the course of this chapter. Let's get started!



Java Swing
Graphic Java 2: Mastering the Jfc, By Geary, 3Rd Edition, Volume 2: Swing
ISBN: 0130796670
EAN: 2147483647
Year: 2001
Pages: 289
Authors: David Geary

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net