How to drag and drop with
Java 2, Part 2 - JavaWorld August
1999
Tutorial Details:
How to drag and drop with Java 2, Part 2
How to drag and drop with Java 2, Part 2
By: By Gene De Lisa
Create a library of drag and drop-enabled Swing components
ow would you like to drag and drop almost any kind of data using almost any project Swing component? The first article in this series, "How to drag and drop with Java 2" (see Resources ), introduced data transfer using familiar drag and drop (D&D) gestures. The first article's examples were limited to a single project Swing component -- a D&D-enabled JLabel. We transferred text data between labels in the same Java virtual machine (JVM), to other JVMs, and to the native system.
This article will show you how to create D&D-enabled versions of many more Swing components. We'll also learn how to transfer various data types beyond plain text.
Custom Transferable classes
In the first article in this series, we discussed how to transfer text. It is, however, possible to drag and drop other data types, such as images and GUI components. In order to transfer other kinds of data, we must create at least one DataFlavor class and a Transferable class.
Previously, we created a StringTransferable class that provided text data in several DataFlavor s. StringTransferable encapsulates a java.lang.String object, which it makes available in these flavors. When the user drops the data onto a droppable component, the component requests the data in its own preferred DataFlavor . Depending on the DataFlavor requested, the String is either simply returned or transformed into a byte stream.
An important point to remember is that a java.lang.String is serializable. If the DropTarget resides in the same JVM, it will receive a reference to a live object. If, however, the DropTarget is in a different JVM, it will receive a serialized copy of the String . The D&D system automatically serializes the String in the same way that RMI parameters are marshalled. We can easily transfer any data encapsulated in a serializable object by defining our own Transferable class.
Create a custom Transferable class
In this example, we'll create a Transferable class for our own Rockhopper class. Rockhopper will be serializable, as will its members; if any are not, we can mark them transient and transfer their data manually via the writeObject() method. This Transferable creates two DataFlavor s for our class. In both DataFlavor s our Rockhopper class is the representation type. The Transferable object simply keeps a reference to the Rockhopper object, which is returned in the getTransferData() method. Remember that, if the DropTarget is in another JVM, the D&D system will automatically serialize the Rockhopper object.
Now, let's look at the code for this example:
public class Rockhopper extends Bird implements Serializable {
private String name; // String is serializable
}
public class RockhopperTransferable
implements Transferable,
ClipboardOwner {
public static DataFlavor rockhopperFlavor=null;
public static DataFlavor localRockhopperFlavor=null;
static {
try {
rockhopperFlavor = new
DataFlavor(com.rockhoppertech.Rockhopper.class,
"Non local Rockhopper");
localRockhopperFlavor = new
DataFlavor(DataFlavor.javaJVMLocalObjectMimeType +
"; class=com.rockhoppertech.Rockhopper",
"Local Rockhopper");
} catch(Exception e) {
System.err.println(e);
}
}
private Rockhopper penguin;
public RockhopperTransferable(Rockhopper rocky) {
this.penguin = rocky;
}
public Object getTransferData(...) {
// check to see if the requested flavor matches
... etc ...
return this.penguin; // easy!
}
etc.
You may want to create a library of Transferable classes for commonly used data types. Popular custom Transferable choices include java.awt.Color , java.util.Date , java.awt.Font , and java.io.File .
Create an Image Transferable class
Creating an Image Transferable class is a bit tricky. The problem is that java.awt.Image isn't serializable, so it can't be used as the representation type for a DataFlavor class. Luckily, javax.swing.ImageIcon is serializable. The ImageIcon maintains a reference to an Image , but it's a transient member. To actually transfer the Image data, the ImageIcon class defines the readObject() and writeObject() methods for manual transfer.
The capability to transfer image data to the native system is more complicated. For native transfers, we need to provide the data as a stream of bytes via an InputStream subclass. For our StringTransferable class, we employed a ByteArrayInputStream object that used the String 's bytes in the proper charset.
Similarly, we can create a JPEGTransferable class that provides the image data in JPEG format. The DataFlavor used by the Transferable can specify image/jpeg and its MIME type. The getTransferData() method can provide the data either via the com.sun.image.codec.jpeg classes or the Java Advanced Imaging API. The latter also provides other formats, such as GIF.
Our JPEGTransferable class will work as long as we have a native program that accepts data with an image/jpeg MIME type. On Windows systems, however, these programs are rare. Most Windows programs accept only Win32 clipboard formats such as DIB (device independent bitmap) or ENHMETAFILE (enhanced metafile). Therefore, for Windows environments you'll need to create InputStream classes that provide the data in one of these formats. Moreover, you'll need to use a special FlavorMap instance.
The FlavorMap class provides mapping between MIME types used in Java and native clipboard types such as DIB or HDROP. The D&D system creates the default FlavorMap from $(JDK)/jre/lib/flavormap.properties . For our custom native InputStreams to be used, we need to add an entry to flavormap.properties . Alternatively, we could create a FlavorMap instance for our listeners.
Here's a custom entry in flavormap.properties :
DIB=image/x-win-bmp;class=com.rockhoppertech.dnd
.datatransfer.DIBInputStream
Build a D&D library
If you need a single D&D-enabled component, you can create a subclass that defines DragGestureListener , DragSourceListener , and DropTargetListener as inner classes. This was the technique used in the first article. If you need a number of D&D-enabled components, you will write very similar code for each component's listeners.
Rather than using inner classes for the listeners, in this article we will use reusable adapters. This makes more sense for a D&D-enabled component library; it should be kept in mind, however, that it is also a bit more difficult to create adapters that will adapt to all possible uses.
The main classes and interfaces in our D&D library include:
DragComponent
DragSourceAdapter
DragGestureAdapter
DropComponent
DropTargetAdapter
A D&D-enabled component would create associations with an instance of each of these classes, as shown in Figure 1.
Figure 1. UML diagram of D&D library classes
The Drag classes
A drag-enabled component implements the DragComponent interface. It creates an instance of DragGestureAdapter and an instance of DragSourceAdapter .
The DragSourceAdapter implements the DragSourceListener interface and maintains a reference to a DragComponent object. When a drag is initiated, the DragSourceAdapter queries the DragComponent for the acceptable drag operation and an appropriate Transferable object. If this is a move operation, the DragSourceAdapter will tell the DragComponent to move the data. The move operation actually adds the data to the destination, then removes the data from the source at the end of the D&D operation. We'll discuss this more when we come to the JList and JTable examples. The drag-over effects are the DragSourceAdapter 's responsibility. These are usually cursor changes. The DragComponent may register custom cursors with the DragSourceAdapter object.
The DragComponent uses a DragGestureAdapter object, which implements the DragGestureListener interface, in order to initiate the drag operation. With components such as a JTree, it is possible that not all nodes can be dragged. The DragGestureAdapter verifies the drag with the DragComponent 's isStartDragOk() method, and it registers the DragComponent 's DragSourceAdapter .
Figure 2. DragComponent message trace
The Drop classes
A drop-enabled component implements the DropComponent interface. It creates and maintains a reference to a DropTargetAdapter .
Figure 3. DropComponent message trace
Transferable models
For some components, we might not want to create an individual subclass for each type of data the component might represent. It would be better to create a transferable model for these components. When the drag operation starts, the component gets the Transferable from the model. This strategy works well for the JTable and JList.
JList
It is convenient to place all of the common D&D methods in an abstract subclass of JList. This abstract DnDList takes care of creating and registering the appropriate adapters, drag-under and drag-over feedback, autoscrolling, moving, and event/flavor validation. The concrete subclass specifies the acceptable operations and flavors, and defines an add() method that is called when the DropTargetAdapter receives the drop message.
We can define a TransferableListModel interface with method public Transferable getTransferable(int index) . For convenience, we can define an AbstractDnDList model that has data structure maintenance code but requires that subclasses implement the getTransferable() method. This concrete subclass determines the exact type of Transferable returned. For example, a DnDTextList concrete subclass of DnDList would create a DnDTextListModel concrete subclass of AbstractDnDList ; the latter in turn creates and returns a StringTransferable object from getTransferable .
Figure 4. D&D list model
JTable
The JTable follows the same pattern as the JList. We place the common D&D code in an abstract class that uses an abstract transferable model. The concrete table subclasses create a concrete t
Read
Tutorial at: Click here to view the tutorial
Rate Tutorial: How to drag and drop with
Java 2, Part 2 - JavaWorld August
1999
View Tutorial: How to drag and drop with
Java 2, Part 2 - JavaWorld August
1999
Related
Tutorials:
Enhance your Java application with Java Native Interface (JNI)
Enhance your Java application with Java Native Interface (JNI) |
Accelerate your RMI
programming
Accelerate your RMI
programming |
XML messaging, Part
3
XML messaging, Part
3 |
Java security evolution
and concepts, Part 2
Java security evolution
and concepts, Part 2 |
Jini's relevance emerges, Part
2
Jini's relevance emerges, Part
2 |
J2SE 1.4
breathes new life into the CORBA community, Part
1
J2SE 1.4
breathes new life into the CORBA community, Part
1 |
A first look at JavaServer Faces, Part I
A first look at JavaServer Faces, Part Learn how to implement Web-based user interfaces with JSF |
Test email components in your software
Test email components in your software |
ULC - J2EE Rich
Clients now on Eclipse
ULC - J2EE Rich Clients now on Eclipse
it is porting ULC Visual Editor to the new Eclipse visual GUI construction and editor platform. The company has been invited to participate in the Eclipse Visual Editor project. Following its decision to contribute |
Worth
reading
Worth
reading |
Very
interesting
Very
interesting |
Hermes JMS Browser
Hermes JMS Browser
Hermes is a Swing application that allows you to interact with JMS providers.
|
JXMLPad 2.3
JXMLPad 2.3
JXMLPad is a pure Swing java component/framework for editing XML/XHTML document.
|
Template-Based Code Generation with Apache Velocity, Part 2
Template-Based Code Generation with Apache Velocity, Part 2
As described in part one of this series, code generation typically uses a template engine to transform some kind of "model" into compilable code, given the formatting specified by a template. |
Java Development on Eclipse, Part 2
Java Development on Eclipse, Part 2
Editor's note: In part one of this two-part series of excerpts from Eclipse, author Steve Holzner provided examples of how Eclipse makes it easier to create Java code from scratch. Continuing in that vein, in this we |
JDBC scripting, Part 2
JDBC scripting, Part 2
Programming and Java scripting in JudoScript
Summary
JudoScript is a rich functional scripting language, and an easy and powerful general programming and Java scripting language.
JudoScript's power comes from its synergy of |
JXMLPad 3.1 FC
JXMLPad is a pure Swing java component/framework for editing XML/XHTML document. |
Unclog the server bottleneck with active containers.
In server-side control architectures such as Java ServerFaces (JSF) or Struts, a majority of the control events must be handled on the server side to update the state of the control. For every user event, the entire page data is sent back to the server... |
Tiger and Beyond, the Future of the Java Platform
Part Two of an interview with Sun Microsystems' Sun Fellow, Graham Hamilton, explores Java 2 Platform, Standard Edition 5.0 (J2SE 5.0) and the future of the Java language. |
J2ME Technology Turns 5!
In 2004 the Java 2 Platform, Micro Edition (J2ME) celebrated its fifth anniversary. This article presents where J2ME is today. |
|
|
|