Anda di halaman 1dari 11

NEWS

How to drag and drop with Java 2, Part 2


Create a library of drag and drop-enabled Swing components
1
By Gene De Lisa
JavaWorld | Aug 20, 1999 1:00 AM PT

How 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
Sign In | Register
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  class and a
 class.
Previously, we created a  class that provided text data in several  s.  encapsulates
a  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  . Depending on the  requested, the  is either simply
returned or transformed into a byte stream.

An important point to remember is that a  is serializable. If the  resides in the same JVM, it will receive a
reference to a live object. If, however, the  is in a different JVM, it will receive a serialized copy of the . The D&D
system automatically serializes the  in the same way that RMI parameters are marshalled. We can easily transfer any data
encapsulated in a serializable object by defining our own  class.

Create a custom Transferable class


In this example, we'll create a  class for our own  class.  will be serializable, as will its members;
if any are not, we can mark them transient and transfer their data manually via the  method. This  creates
two  s for our class. In both  s our  class is the representation type. The  object simply
keeps a reference to the  object, which is returned in the  method. Remember that, if the  is
in another JVM, the D&D system will automatically serialize the  object.
Now, let's look at the code for this example:

publicclassRockhopperextendsBirdimplementsSerializable
privateString//Stringisserializable

publicclassRockhopperTransferable
implementsTransferable
ClipboardOwner
publicstaticDataFlavor null
publicstaticDataFlavor null
static
try
 new
DataFlavorRockhopperclass

 new
DataFlavorDataFlavor 


catchException
System


privateRockhopper
publicRockhopperTransferableRockhopper
this

publicObject
//checktoseeiftherequestedflavormatches

returnthis//easy!


You may want to create a library of  classes for commonly used data types. Popular custom  choices
include , , , and .

Create an Image Transferable class


Creating an  class is a bit tricky. The problem is that isn't serializable, so it can't be used as the
representation type for a  class. Luckily, is serializable. The maintains a reference to an
, but it's a transient member. To actually transfer the data, the class defines the  and
 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  subclass. For our  class, we employed a   object that
used the 's bytes in the proper charset.
Similarly, we can create a 
 class that provides the image data in JPEG format. The  used by the
 can specify image/jpeg and its MIME type. The  method can provide the data either via the
classes or the Java Advanced Imaging API. The latter also provides other formats, such as GIF.
Our 
 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
 classes that provide the data in one of these formats. Moreover, you'll need to use a special  instance.
The  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  from . For our custom native  to be used,
we need to add an entry to . Alternatively, we could create a  instance for our listeners.
Here's a custom entry in :
 class
DIBInputStream

Build a D&D library


If you need a single D&D-enabled component, you can create a subclass that defines 
, , and
 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&Denabled 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:







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  interface. It creates an instance of 


 and an instance of
.
The  implements the  interface and maintains a reference to a  object. When a
drag is initiated, the  queries the  for the acceptable drag operation and an appropriate
 object. If this is a move operation, the  will tell the  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 's responsibility.
These are usually cursor changes. The  may register custom cursors with the  object.
The  uses a 
 object, which implements the 
 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 
 verifies
the drag with the 's  method, and it registers the 's .

Figure 2. DragComponent message trace

The Drop classes


A drop-enabled component implements the  interface. It creates and maintains a reference to a .

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
 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  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 method that is called when the
 receives the drop message.
We can define a  interface with method . For convenience,
we can define an  model that has data structure maintenance code but requires that subclasses implement the
 method. This concrete subclass determines the exact type of  returned. For example, a 

concrete subclass of  would create a  concrete subclass of ; the latter in turn creates and
returns a  object from .

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 transferable model.

Figure 5. D&D table model

JTree
It isn't necessary to create a  model for the JTree. The tree nodes may contain a user object. If this object is serializable,
you can define a  class with a  that uses a  as its representation class.
What does it mean to copy a tree node? Do you want to copy just the node, or all of its children? We will address these issues below,
when we talk about the JTree in more detail.

Issues for drag and drop components

When you create a D&D-enabled component, there are several issues you need to address:
Starting the drag operation
Drag-under feedback
Drag-over feedback
The drop


The move operation


I will address each of these issues for three complex components -- the JList, the JTable, and the JTree -- with the help of our D&D
library classes. First however, let's examine these issues in a general sense.

Starting the drag operation


Is it OK to start dragging at the current pointer location? Perhaps the component is a JTree and the selected tree node cannot be
dragged. The 
 object calls the  method of our  object. If the return value is ,
the drag simply will not start.

Drag-under feedback
How do we show that a drop is valid? If, for example, the component is a JList, where will the drop occur? To show the user where
the data will be inserted, define the  and  methods from our  interface.

Drag-over feedback
Most of the time, the default drag-over feedback is fine. However, there could be a situation in which you would like to use custom
cursors. The  calls the 's  method repeatedly during the drag. The return value sets the
drag-over feedback. For most components the initial cursor should be a no-drop cursor, since dropping the data in the same place as
its origin is useless.

The drop

If you accept the dropped data, you insert it someplace in the component. Where is it going to be inserted? What flavors are
accepted?

Transferable
What / class should you use? When a drag starts, how do you get the  object? The 
object may encapsulate data associated with the component or data retrieved from its model. Our 
 calls the
's  method.

The move operation


Because it's a two-step process, the move operation actually removes the data. The D&D system adds the data to the destination and
then removes it from the source. If it's a complex component, such as a JList, which item is removed? The  calls
the 's method.

JList
Now, let's look at possible solutions for each of the issues we've just raised in the context of a D&D-enabled JList.

Starting the drag


Remember that, with a list and a table, you get the  from the model. Since our drag-under feedback selects the item
that is under the pointer, we can get the  from the model at the selected index. We must remember this index, since a
move operation will remove the item from the model.

Drag-under feedback

NEXT

View 1 Comment

Copyright 1994 - 2016 JavaWorld, Inc. All rights reserved.

Anda mungkin juga menyukai