Download as pdf or txt
Download as pdf or txt
You are on page 1of 10

Sign In | Register

NEWS

How to drag and drop with Java 2, Part 2


Create a library of drag and drop-enabled Swing components

By Gene De Lisa
JavaWorld | Aug 20, 1999 1:00 AM PT

Page 2 of 3
Selecting the item under the pointer provides intuitive drag-under feedback. The pointer location can be retrieved from the
 object by its  method. This location can be turned into an index with the JList 
method. If the returned index is , we need to clear the selection, since the pointer isn't over any item. Otherwise, we select the item
at the returned index. If the drop cannot take place at the selected index, we can change the background color to red and reset it to
the default selection color when the drop is OK. To undo the drag-under feedback, we can simply clear the selection.

Drag-over feedback
With the  method, we can determine if the pointer is currently over an item or not. If the value returned from the
 method is , the return value should be . The adapter will then set the no-drop cursor. One special case is
that if the model is empty, the  method will always return , since there are no items over which the pointer can
be. Therefore, we should check to see if the model size is and return if it is.

The drop

The combination of our drag-over and drag-under feedback ensures that there will be an item selected when the drop occurs. Should
we insert the data before or after the item selected by our drag-under feedback?
One way to determine this is to make it a user preference. We need to remember which index we insert the data into, since it will be
used in the method.

The Transferable
Since the JList may contain many different kinds of data, we rely on the  to provide the . The
JList only needs code to find the selected index and to get the  from the model at that index. Here, too, we must
remember the selected index, since it will be needed in the case of a move operation.
Here's the code:
this this 
returnthisthis

The move operation


We need to remember both the index of the item used to create the  and the index where the item was inserted. If the
same JList is both the source and destination, we can't simply remove the item at that index. The dropped data is added before the
move operation. If the dropped data is inserted at an index that is less than the original index, it will be off by one.
If the move operation isn't local, we can simply remove the element at that index.
Let's look at this in detail:

publicvoid
ifthislocal
ifthis this 
this 

thisthis 

JTree
For each of the D&D issues, we will now discuss possible solutions for a D&D-enabled JTree.

Starting the drag


There's no easy way to get the node at the current pointer location. To do so, you need to get the  at the location and get
the last path component from it. If the user is currently editing a node, stop the edit before starting the drag.
Now, let's examine how this works:
protectedDefaultMutableTreeNodePoint
TreePaththis 
ifnull
returnDefaultMutableTreeNode
else
returnnull


Drag-under feedback

You might want to expand the node under the pointer and select the node that the pointer is over. Display invalid feedback if this
node doesn't accept children.

Drag-over feedback
You can check to see if the node under the pointer allows children. If not, return from the  method to show the nodrop cursor.

The drop
If the drop is local and the operation is to copy, you probably want to create a copy of the node rather than simply insert the node.
Otherwise, when either of the nodes (the original or the copy) is modified, the other will be as well. You might also want to make a
deep copy of the dropped node. The default method makes a shallow copy. You need to write your own deep-copy code. You
can do this with the  and  methods.

The Transferable
Create a  object from the node under the current pointer location. Then save a reference to this node.

The move operation


Remove the node that was used to create the  object with method  .

JTable
The JTable has many of the same issues as the JList.
The table is a view of the data in its model. If each table cell represents an object in the model, you may want to create a table in
which the user can drag and drop individual cells. If the table maps each object to a row and the table columns to the object's
attributes, you might want the user to be able to drag and drop a table row.

One frequent question that comes up in such situations is how to drop onto an empty table or a table with empty cells. For example,
the table could represent the innings in a baseball game. If the game is in progress, the table's later innings would be empty. (This is
more of a model question than a D&D issue.) One way to solve the problem is for the game model to start with nine default inning
objects. At the end of each inning the user can drop the new inning onto the table to replace the default one. A more efficient answer
for a situation with a large number of cells is to create a model that uses a sparse collection.

Starting the drag


In addition to verifying that the data under the pointer is draggable, you need to check to see if an edit is in progress. If so, stop the
edit with the  method.

Drag-under feedback
You can select the cell or row under the pointer for drag-under feedback. To accomplish this, use methods  and/or
 to determine which row or cell the pointer is over.

Drag-over feedback
You may want to check the row and column at the current point and veto some cells. If you save the row and column that you used to
create the  object, you can prevent dragging and dropping on the same cell. You can also retrieve the row and column
counts from the model. If the calculated row or column is greater than the model's row or column count, you may want to veto the
drop.

The drop
Does the drop replace the selected row or cell, or does it insert a new row or cell? If it isn't a local drop, it is possible that an edit is
in progress. Stop the editing, then either use the  method to replace the selection or create a method in
the model that allows insertion before or after the selection.

Transferable

Retrieve the  object from the model. Use the selected row and/or column to allow the model to determine how to make
the . If the table drags and drops rows, the selected column is ignored.

The move operation


Save the row and column of the node used to create the . Use   to remove the node.

Composite components
Components such as the  and  are composed of several other components. In this section, we discuss the
issues involved with adding D&D capability to these components

JFileChooser and GlassPanes


The  contains , a , , and a  . If you create a  subclass and use either
inner class listeners or adapters, the D&D operation may occur only where there are no children visible. This situation will not be
intuitive for the user.
As a solution, we create a special glass pane that implements the drag and/or drop listeners. When visible, the glass pane would need
to forward mouse events to the child components. For the , the glass pane can be created and installed in the
 method. The  s that this glass pane should accept include   . For a drag
operation, the 's selected file is used to create an instance of our custom  class.
Now, let's take a look in detail:
LinkedListnewLinkedList
this 
returnnewFileTransferable
To retarget mouse events, you can get a head start by borrowing parts of the
 inner class from the
  class. However, the
 must be modified to work with . The  children
of the  would not work otherwise, since combination boxes use a . Moreover, menus in a menu bar won't

work either. We need to make the glass pane invisible when a popup is visible in order to make popups work correctly. The
 class can help to determine if a popup is visible:
MenuSelectionManager
MenuSelectionManager
MenuElement
If the selected path is greater than zero and the mouse event is a press (the instant in time when the user depresses the mouse
button, but has not yet released it) or a click (a press followed by a release), you need to set the glass pane as invisible. The selected
path can search for an instance of a . If one is found, a  can be installed that will make the glass pane
visible again when the popup becomes invisible.

JColorChooser
The glass pane technique doesn't work well with a  component. The  object uses a ,
which doesn't handle mouse events correctly on tabs beyond the first one. The  may be modified to work correctly, but
that doesn't help with the  unless a new UI is installed. Also, since the glass pane forwards events to the children, the
 children would interfere with the drag gesture.
The current solution is to write a new UI delegate with corrected  and D&D-enabled components. You can install your
D&D-enabled versions of the , , and 
 classes either by your own
 class or by the 's  method. It would be convenient if you were able
to set the  , but that isn't currently possible. This  bug (actually it's a  bug) is in the list
of outstanding bugs and will be fixed in a future release of the JDK.

InternalFrame
A common problem with the is that D&D seems to work at first, but breaks down when an internal frame is selected.
The mystery is that when an internal frame is not selected, its glass pane becomes visible and catches events. This bug results from
the user's need to be able to select an inactive frame by pressing the mouse anywhere on the internal frame. This bug was
supposedly fixed in the JDK 1.2.2 release. In this release you were, in fact, able to drop onto the frame's children. However, the fix
seems to have introduced a selection-repaint bug where the previous selection isn't completely cleared during a drag.

One solution is to install another special glass pane that is a  on each internal frame. This glass pane will forward
mouse events to the internal frame's child components. We can reuse our modified
 for this. The only
modification to the dispatcher is to select the glass pane's internal frame on mouse-press events. A complication is that this glass
pane cannot dispatch D&D events (as it can ) since they are not  subclasses.

JApplet
You can use D&D in an applet if your browser supports Java 2 or if you can use the Java 2 plugin. There are two steps to enable D&D
in an applet. First, the applet needs permissions granted in a policy file:

AWTPermission
AWTPermission
AWTPermission
AWTPermission
AWTPermission

To use this policy (in a file named ) with , use this command:

 Djava
(Policy files have been discussed elsewhere in JavaWorld, see Resources for URLs.)
Second, s will not work if you create them in either the or methods. If you do create them in these
methods, you will be able to drag, but not drop.
Below is an example of a JApplet that contains D&D-enabled children. The  method will create these
components and add them to the content pane. You will also want to check to see if this is the first time that the start message has
been received. Otherwise, you'd be adding many components!

publicvoid
//dothisonlythefirsttimestartiscalled
ThreadnewThreadthis


publicvoid
this
JPanelJPanel


If the JApplet itself is a drop site, you'll need to create the  the same way -- in a separate thread. In addition, you'll need to
specify the content pane as the 's component:
publicvoid
this
JPanelJPanel


void
thisnewDropTargetAdapter
thisnewDropTargetthis
DnDConstants 
this
true


PREVIOUS

NEXT

View Comments

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

You might also like