For the JavaTM 2 Platform, Standard Edition, v 1.4 release, Swing has added support for data transfer between applications. A drag and drop operation is a data transfer request that has been specified by a gesture with a graphical pointing device. In the case of copy/paste, data transfer is often initiated with the keyboard. The ability to transfer data takes two forms:
Because the state of each Swing component is independent of the definition of the data model, it was easy to implement a mechanism for moving the data between components without worrying about the details of the data itself. The data transfer amounts to transferring part of one model to another model. (In the case of cut/copy/paste, the data is transferred between the model and the clipboard.) To support data transfer, we:
Component | Supports Drag | Supports Drop |
---|---|---|
JColorChooser
| ||
JEditorPane
| ||
JFileChooser
| ||
JFormattedTextField
| ||
JLabel
| see here | see here |
JList
| ||
JPasswordField
| ||
JTable
| ||
JTextArea
| ||
JTextField
| ||
JTextPane
| ||
JTree
|
This document has the following sections:
The foundation of data transfer is support
for handling the transfer of data into and out of a component.
With this functionality available on the component, the mechanics
of managing a drag and drop can be provided automatically.
In addition, support for cut/copy/paste can also be provided
automatically. The crux of this implementation is the new
class
TransferHandler
. The
JComponent
property methods,
setTransferHandler
and
getTransferHandler
, provide an entrypoint to the
data transfer mechanism for any component which extends
JComponent
.
The table below details the extent of the cut, copy, paste, and
drop support for each of the components when a non-null
TransferHandler
is installed. Note that this support
is enabled by the look and feel code. Support for dragging is
initially disabled, but may be enabled by calling
setDragEnabled(true)
on the component. If the
component doesn't have such a method, the drag may be enabled
by binding some kind of gesture to it.
TransferHandler
. For those
components that have default Swing support, the
TransferHandler
is
installed by the ComponentUI
if the value of the
transferHandler
property is null
or
marked by the presence of the UIResource
interface.
The default TransferHandler
implementation installed
by the ComponentUI
is marked by the
UIResource
interface, enabling developers to
override the default TransferHandler
.
The following table shows the support provided.
Component | Exports (Drag, Cut, Copy) | Imports (Drop, Paste) |
---|---|---|
JColorChooser
| The selected color is offered through the
JavaBeansTM
property handling of TransferHandler .
The flavor offered is
application/x-java-jvm-local-objectref; class=java.awt.Color .
The value transferred is determined by getColor .
| Accepts inserts of type Color .
The data is imported by using setColor (from the
bean property handling). Any flavor having
class=java.awt.Color (or a subclass of
java.awt.Color ) is accepted.
|
JEditorPane
| 1.4: If the content-type of the JEditorPane
is text/plain , the selected text is offered as
as text/plain through the write method
of the EditorKit .
If the content-type is OTHER , it
is exported both as text/plain using the
getSelectedText method, and as OTHER
using the write method of the EditorKit .
1.4.1: The selected text, as returned by the
| 1.4: Accepts inserts of type text/plain and
whatever the current type returned by getContentType .
If a type is found matching the current type
(including text/plain ), it is imported using
the EditorKit 's read method.
Otherwise, text/plain is imported through the
component's replaceSelection method.
Paste: the contents of the selection, if any, are replaced.
Drop: the data is inserted at the caret position.
1.4.1: Accepts inserts of type |
JFileChooser
| The selection is offered in the same manner as those from the native file chooser. | Imports not accepted. As the mouse is moved over the list, the potential drop point is indicated by highlighting the file/directory under the cursor. See Default Drop Support. |
JFormattedTextField
| The selected text is offered as text/plain .
| Accepts inserts of type text/plain .
Paste: the contents of the selection, if any, are replaced;
otherwise the data is inserted at the caret position.
Drop: the data is inserted at the caret position.
Note that paste and drop employ the same code paths as
typing from the keyboard, therefore code validation is preserved.
|
JList
| If the selection is a single item, it is offered as
text/plain . If multiple items are selected,
they are offered as text/html .
The format of the text/html is a <UL>
tag followed by the selected list items
each starting with an <LI> tag.
| Imports not accepted. As the mouse is moved over the list, the potential drop point is indicated by highlighting the list item under the cursor. See Default Drop Support. |
JPasswordField
| For security reasons, cut, copy, and drag are not supported. | Accepts inserts of type text/plain .
Paste: the contents of the selection, if any, are replaced;
otherwise the data is inserted at the caret position.
Drop: the data is inserted at the caret position.
|
JTable
| If the selection is a single item, it is offered as
text/plain . If multiple items are selected,
they are offered as text/html .
The format of the text/html is a <TABLE>
tag followed by a <TR> tag for each row
and a <TD> tag for each cell.
| Imports not accepted. As the mouse is moved over the table, the potential drop point is indicated by highlighting the cell under the cursor. See Default Drop Support. |
JTextArea
| The selected text is offered as text/plain .
| Accepts inserts of type text/plain .
Paste: the contents of the selection, if any, are replaced;
otherwise the data is inserted at the caret position.
Drop: the data is inserted at the caret position.
|
JTextField
| The selected text is offered as text/plain .
| Accepts inserts of type text/plain .
Paste: the contents of the selection, if any, are replaced;
otherwise the data is inserted at the caret position.
Drop: the data is inserted at the caret position.
|
JTextPane
| Same as JEditorPane .
| Same as JEditorPane .
|
JTree
| If the selection is a single item, it is offered as text/plain .
If multiple items are selected, they are offered as text/html .
The format of the text/html is nested lists,
similar to the format used for JList .
| Imports not accepted. As the mouse is moved over the table, the potential drop point is indicated by highlighting the tree node under the cursor. See Default Drop Support. |
JLabel
The
JLabel
component does not support DnD by
default. The following code fragment creates a JLabel
that supports drag and drop on the "text" property (a
String
):
JLabel componentType = new JLabel(); componentType.setTransferHandler(new TransferHandler("text")); MouseListener ml = new MouseAdapter() { public void mousePressed(MouseEvent e) { JComponent c = (JComponent)e.getSource(); TransferHandler th = c.getTransferHandler(); th.exportAsDrag(c, e, TransferHandler.COPY); } }; componentType.addMouseListener(ml);
We have included a small example that implements drag
and drop using a JTextField
and a JLabel
.
You can type a value into the text field, highlight the
text, then hold the mouse button down over the textfield and
drag a few pixels. An icon appears under the cursor.
Release the icon over the JLabel
and see the
text replace the "Drop Here" text. Simultaneously with the
drop, the text is removed from the source textfield.
The default behavior for
drag and drop is MOVE
. To change the behavior to
COPY
, hold down the CONTROL
key
while selecting the text. On Windows, a plus sign appears
in the icon. When the text is released on the target, it
is left intact in the source. You can likewise drag
from the JLabel
to the text field.
Note that JLabel
does not have bindings for
copy/paste and is unable to get the focus that is required to support
this feature.
See the JLabelDragNDrop.java example here.
Some components, such as text fields, support selections.
For those kinds of components,
a drag operation is typically initiated by dragging an existing
selection with the mouse. A controller for this type of component
can recognize this
condition and initiate a drag. For those components that don't
have selections, Swing can't automatically initiate the drag,
but Swing can handle the mechanics of the drag if
told that a drag attempt has been initiated as shown in the
JLabel
example.
With this level of drag support, the Swing developer can
focus on implementing a TransferHandler
that represents
the desired transfer, and setting properties on the
Swing component. This greatly simplifies the burden to the
Swing developer wanting to support dragging in an application.
Note that we are currently investigating providing different
visual appearances of the drag, hence the reference to
Icon
in the API. Stay tuned for future developments.
The simplest level of support is to set a flag that indicates
the developer would like the default support enabled.
The components that offer default support for dragging
are described in the Exports column
of the Components That Support
DnD table; but to summarize, the classes that directly implement
setDragEnabled
and
getDragEnabled
are:
JColorChooser
,
JFileChooser
,
JList
,
JTable
,
JTree
, and
JTextComponent
.
The drag gesture is defined as the
press of the first mouse button over a selection and dragging
a few pixels. Setting the dragEnabled
property
to true
therefore has a subtle effect on mouse behavior.
When dragging is enabled on a component, the
Swing controller (in the corresponding ComponentUI
subclass) begins looking for a drag gesture, and if the
transferHandler
property is null
,
or marked by the presence of the
UIResource
interface, a default implementation is installed.
The implementation provided by Swing is marked with the
UIResource
interface, so a developer can insert
a new TransferHandler
by replacing
the default TransferHandler
property with a
custom implementation. When a drag gesture is recognized,
the
exportAsDrag
method is called on the
TransferHandler
which initiates the drag mechanism.
The actual transfer is handled by the
java.awt.dnd
mechanism, requiring no further effort from the developer.
The drag support provided by Swing is activated by the
TransferHandler.exportAsDrag
method.
This makes adding drag support as easy as:
TransferHandler
implementation
(so there is something to drag) by calling the
setTransferHandler
method.
exportAsDrag
method.
Some scenarios for accomplishing this are:
MouseListener
that watches for the
desired gesture, then call getTransferHandler
on the component and call the exportAsDrag
method
when the desired gesture is found. See the
JLabel example.
processMouseEvent
method in a
subclass and call the exportAsDrag
method on
the ComponentUI variable when a drag gesture is seen, otherwise execute
the superclass behavior.
exportAsDrag
when a drag gesture
has been seen.
When the exportAsDrag
method is called on
TransferHandler
, the drag is handled by Swing
provided functionality. When this method is called, it is assumed
that a valid drag gesture has been recognized. The method
performs the following steps:
DragSource
and
DragListener
is used to start the drag using the
Transferable
implementation returned by
createTransferable
as data transfer object.
exportDone
method is called on the TransferHandler
.
For some operations, such as MOVE
, it may
be necessary to remove the data from the source.
The default behavior for text-based components, for example,
is that a standard drag implements MOVE
behavior
(following the drop the selected text is removed from the
source component). The user may override this behavior by holding
down the control key when the text is selected for dragging.
On Windows, the drag icon visually reflects this behavior
with a small plus-sign.
The primary support for handling a drop is the same as for
a paste operation, the
importData
method
on the TransferHandler
. The semantics of inserting data
into a component are generally more meaningful at the
application level than the toolkit level. Users of an application
can drop all kinds of Transferable
implementations on
components that are completely unknown to the Swing toolkit.
It is up to the Swing developer to
provide a TransferHandler
with meaningful import
semantics if the default TransferHandler
is insufficient.
A drop operation does have some differences from a paste however:
To assist Swing developers in adding drop support to an
application, Swing provides DropTarget
implementations that use the TransferHandler
property on the Swing component. For those components that
have a non-null
TransferHandler
property,
the drop target is installed by the ComponentUI
if the value of the dropTarget
property is
null
or marked by the presence of the
UIResource
interface.
The default DropTarget
implementations installed
by the ComponentUI
is marked by the
UIResource
interface, enabling developers to
override the default DropTarget
.
The components that provide a complete drop implementation
by default are indicated in the
Imports column of the
Components That Support DnD table.
There are four components that provide only some support for drop.
JFileChooser
,
JList
, JTable
, and JTree
by default have an installed DropTarget
that
indicates a potential insertion point. However, to fully support imports
of data the developer must write and install a
custom TransferHandler
.
A well behaved DropTarget implementation uses the
transferHandler
property on JComponent
to perform the drop. The Swing developer automatically
gets a simple DropTarget
implementation that links
the drop to the TransferHandler
when the
transferHandler
property is set and the
dropTarget
property is null
.
Cut, copy, and paste operations perform data transfer in a
manner that is more useful to those without a mouse, as they
are typically initiated via a keyboard gesture. These operations
can use the same TransferHandler
services as the
drag and drop support. This improves the accessibility of the
data transfers, and enables Swing to provide keyboard bindings
for these operations even though Swing may not know how to actually
transfer the data to/from the clipboard. The keyboard bindings
for clipboard transfer are dependent upon the current look and
feel that is installed.
As with drag and drop, clipboard transfers are the most useful for those components that support selections. The list of components shown in the Exports column of the Components That Support DnD table have cut, copy, and paste actions in the component action map, along with a LAF dependent set of keyboard bindings in the input map of the component. Having Swing provide these bindings frees the developer from trying to track the current look and feel and change the bindings.
A well behaved cut, copy, and paste implementation uses
the transferHandler
property on JComponent
to perform the transfer. When the transferHandler
property is set on a JComponent
, a simple
Action
implementation that links the transfer of between a
Clipboard
and TransferHandler
is installed in the component's action map under the
keys cut
, copy
, and paste
if there is no action currently installed.
Note: The following information outlines private implementation details and is subject to change. We are providing this information only to satisfy the curiosity of those who have access to the source code and feel compelled to thump the tires and peek under the hood.
If a TransferHandler
is installed on a
JComponent
, the look and feel then enables
cut, copy, and paste
using the following TransferHandler
methods:
TransferHandler.exportAsDrag
you also get
drag support.
This plumbing is located in package-private nested classes inside of
the TransferHandler
class.
The following package-private classes were added to the
javax.swing.plaf.basic
package for creating
the default support:
BasicTransferable
Transferable
implementations.
BasicDropTargetListener
BasicDragGestureRecognizer
Each of the ComponentUI
classes that support
DnD then have some additional nested classes:
BasicTreeUI
:
TreeTransferHandler
- Default import/export support.
TreeTransferable
- The actual tree data.
TreeDragGestureRecognizer
- Tree drag gesture recognition, enabled by
JTree.setDragEnabled
.TreeDropHandler
- Shows drop target location.
BasicListUI
, BasicTableUI
,
BasicTextUI
all have a pattern similar to
as BasicTreeUI
.
BasicFileChooserUI
FileTransferHandler
that produces
the FileTransferable
that extends
the ListTransferable
with the flavor
used for file transfers.
BasicColorChooserUI
TransferHandler
bean support
and binds the "color" property. A mouse listener is
added to the preview area to bind a mouse press to
the exportAsDrag
method on the
TransferHandler
.
TransferHandler Actions Should be Registered by UI
The bugtraq report that corresponds to this change is: 4460011.
To implement drag and drop, bindings were provided in the
Action
class to support copying and pasting the data. In order for a look and feel, or other code, to override theseAction
s, the UI must install them -Action
s are no longer automatically installed by theTransferHandler
. The package-private methodsgetCutAction
,getCopyAction
, andgetPasteAction
inTransferHandler
are now made public.Ability to Disable DropTarget
The bugtraq report that corresponds to this change is: 4485914.
The drag and drop implementation causes a
DropTarget
to be added to aJComponent
if that component has aTransferHandler
installed. This may affect applications that are manually addingDropTarget
s. Therefore the System propertysuppressSwingDropSupport
has been added. TheJComponent
methodssetTransferHandler(TransferHandler)
andgetTransferHandler
can be used to enable or disable this property.
Drop Clobbers Selected Text in JTextComponent
The bugtraq report that corresponds to this problem is: 4513715.
Selecting text and then dragging and dropping that text within the selected region of the same text component causes the selected text to be clobbered and nothing to be pasted. This bug is fixed in release 1.4.1.
Occasional Errors in Restoring Caret when Exiting a Component
The bugtraq report that corresponds to this problem is: 4513720.
With the built-in drop support, Swing text components respond to DnD dragovers by setting the
Caret
to visible and using it to display the potential insert location. When the drag exits the component, theCaret
's visibility is restored. Unfortunately, since theCaret
uses the same "visible
" property to represent the usual meaning of visible as well as when it is in mid-flash, we sometimes restore the Caret's visibility incorrectly.Cut/Copy/Drag Broken for JEditorPane with RTFEditorKit
The bugtraq report that corresponds to this problem is: 4513638.
When using an
RTFEditorKit
set explicitly on aJEditorPane
usingsetEditorKit
, or by setting thecontent-type
totext/rtf
, cut, copy and drag no longer work. Note that this bug, filed against release 1.4, is fixed in release 1.4.1.