For the Java 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 |
Yes | Yes |
JEditorPane |
Yes | Yes |
JFileChooser |
Yes | No |
JFormattedTextField |
Yes | Yes |
JLabel |
see here | see here |
JList |
Yes | No |
JPasswordField |
No | Yes |
JTable |
Yes | No |
JTextArea |
Yes | Yes |
JTextField |
Yes | Yes |
JTextPane |
Yes | Yes |
JTree |
Yes | No |
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
JavaBeans 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 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
TreeTransferable
TreeDragGestureRecognizer
JTree.setDragEnabled
.TreeDropHandler
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
.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 these
Action
s, the UI must install them -
Action
s are no longer automatically installed by the
TransferHandler
. The package-private methods
getCutAction
,
getCopyAction
, and
getPasteAction
in TransferHandler
are now made public.
The bugtraq report that corresponds to this change is: 4485914.
The drag and drop implementation causes a
DropTarget
to be added to a JComponent
if
that component has a TransferHandler
installed. This
may affect applications that are manually adding
DropTarget
s. Therefore the System property
suppressSwingDropSupport
has been added. The JComponent
methods
setTransferHandler(TransferHandler)
and
getTransferHandler
can be used to enable or disable this
property.
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.
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, the Caret
's visibility is
restored. Unfortunately, since the Caret
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.
The bugtraq report that corresponds to this problem is: 4513638.
When using an RTFEditorKit
set explicitly on a
JEditorPane
using setEditorKit
, or by
setting the content-type
to text/rtf
,
cut, copy and drag no longer work. Note that this bug, filed
against release 1.4, is fixed in release 1.4.1.