| ★ wanayoo — archive 1999 http://developer.java.sun.com/developer/Books/MasteringJava/Ch16/index.html | Nouvelle recherche | Portail wanayoo |
|
|
Mastering JavaTM 2
|
|
The program behind the application shown in Figure 16.1 follows. Be sure to try pasting from external applications, not just from what was copied with the program.
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
import java.awt.datatransfer.*;
import java.io.IOException;
public class ClipIt {
public static void main (String args[]) {
final Clipboard clipboard =
Toolkit.getDefaultToolkit().getSystemClipboard();
JFrame f = new JFrame ("Clip It");
f.addWindowListener (new WindowAdapter() {
public void windowClosing (WindowEvent e) {
System.exit (0);
}
});
Container c = f.getContentPane();
final JTextArea jt = new JTextArea();
JScrollPane pane = new JScrollPane (jt);
c.add (pane, BorderLayout.CENTER);
JButton copy = new JButton ("Copy");
copy.addActionListener (new ActionListener() {
public void actionPerformed (ActionEvent e) {
String selection = jt.getSelectedText();
StringSelection data = new StringSelection(
selection);
clipboard.setContents (data, data);
}
});
JButton paste = new JButton ("Paste");
paste.addActionListener (new ActionListener() {
public void actionPerformed (ActionEvent e) {
Transferable clipData = clipboard.getContents
(clipboard);
if (clipData != null) {
try {
String s = (String)(clipData.getTransferData
(
DataFlavor.stringFlavor));
jt.replaceSelection (s);
} catch (UnsupportedFlavorException ee) {
System.err.println ("Unsupported flavor:
" + ee);
} catch (IOException ee) {
System.err.println ("Unable to get data:
" + ee);
}
}
}
});
JPanel p = new JPanel();
p.add (copy);
p.add (paste);
c.add (p, BorderLayout.SOUTH);
f.setSize (300, 300);
f.setVisible (true);
}
}
NOTE:
Java does not currently support pasting objects like images from external applications. You could copy an ImageIcon and treat it as a javaSerializedObjectMimeType. However, it would then only be pasteable into another Java program, or a program that understands Java's serialization mechanism, which will be described in the "Object Persistence and Serialization" section of Chapter 19.
public interface DragSourceListener extends EventListener{
public abstract void dragDropEnd(
DragSourceDropEvent e);
public abstract void dragEnter(
DragSourceDragEvent e);
public abstract void dragExit(
DragSourceEvent e);
public abstract void dragOver(
DragSourceDragEvent e);
public abstract void dropActionChanged(
DragSourceDragEvent e);
}
While the target implements DropTargetListener:
public interface DropTargetListener extends EventListener{
public abstract void
dragEnter(DropTargetDragEvent e);
public abstract void
dragExit(DropTargetEvent e);
public abstract void
dragOver(DropTargetDragEvent e);
public abstract void
drop(DropTargetDropEvent e);
public abstract void
dropActionChanged(DropTargetDragEvent e);
}
One thing should be pointed out. There are three different event types for
each set of five methods: DragSourceEvent,
DragSourceDragEvent, and DragSourceDropEvent for
dragging; and DropTargetEvent, DropTargetDropEvent,
and DropTargetDragEvent for dropping. This requires a little
extra care when implementing each interface.
The source of a dragging is a DragSource. The draggable object
would create an instance of DragSource within its constructor.
public class DragSource extends Object{
public static final Cursor DefaultCopyDrop;
public static final Cursor DefaultCopyNoDrop;
public static final Cursor DefaultLinkDrop;
public static final Cursor DefaultLinkNoDrop;
public static final Cursor DefaultMoveDrop;
public static final Cursor DefaultMoveNoDrop;
public DragSource();
public static DragSource getDefaultDragSource();
public static boolean isDragImageSupported();
public DragGestureRecognizer createDefaultDragGestureRecognizer(
Component target,
int actions,
DragGestureListener l);
public DragGestureRecognizer createDragGestureRecognizer(
Class recognizerAbstractClass,
Component target,
int actions,
DragGestureListener l);
protected DragSourceContext createDragSourceContext(
DragSourceContextPeer
dscp,
DragGestureEvent dgl,
Cursor dragCursor,
Image dragImage,
Point imageOffset,
Transferable t,
DragSourceListener l);
public FlavorMap getFlavorMap();
public void startDrag(
DragGestureEvent trigger,
Cursor dragCursor,
Image
dragImage,
Point dragOffset,
Transferable t,
DragSourceListener l)
throws InvalidDnDOperationException
public void startDrag(
DragGestureEvent trigger,
Cursor dragCursor,
Image
dragImage,
Point imageOffset,
Transferable t,
DragSourceListener l,
FlavorMap map)
throws
InvalidDnDOperationException;
public void startDrag(
DragGestureEvent trigger,
Cursor dragCursor,
Transferable t,
DragSourceListener l)
throws InvalidDnDOperationException;
public void startDrag(
DragGestureEvent trigger,
Cursor dragCursor,
Transferable t,
DragSourceListener l,
FlavorMap map)
throws InvalidDnDOperationException;
The other thing you must do in the constructor is create a
DragGestureRecognizer. Since detecting when the dragging
has started is platform specific, this is available from the
Toolkit via createDragGestureRecognizer().
Instead of asking the Toolkit for the recognizer, there is
a convenience method
createDefaultDragGestureRecognizer() available
from DragSource that both creates the recognizer
and registers a DragGestureListener.
public interface DragGestureListener
extends EventListener {
public abstract void dragGestureRecognized(
DragGestureEvent e);
}
It is within this dragGestureRecognized() method that you
notify the DragSource the dragging has started and call its
startDrag() method.
To put all this together, create a draggable JLabel
object. This involves subclassing JLabel and implementing
DragSourceListener and DragGestureListener.
The actual DragSourceListener methods do nothing, as all
the work will be in the dragGestureRecognized() method.
import java.awt.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import com.sun.java.swing.*;
import com.sun.java.swing.event.*;
public class DraggableLabel extends JLabel implements
DragSourceListener,
DragGestureListener {
DragSource dragSource;
public DraggableLabel(String s) {
super (s);
dragSource = new DragSource();
dragSource.createDefaultDragGestureRecognizer(this,
DnDConstants.ACTION_COPY, this);
}
public void dragGestureRecognized(
DragGestureEvent e) {
StringSelection text =
new StringSelection(getText());
dragSource.startDrag(
e,
DragSource.DefaultCopyDrop,
text,
this);
}
public void dragDropEnd (DragSourceDropEvent e){}
public void dragEnter (DragSourceDragEvent e){}
public void dragExit (DragSourceEvent e){}
public void dragOver (DragSourceDragEvent e){}
public void dropActionChanged (DragSourceDragEvent e){}
}
The only part not explained yet is the DnDConstants.
The different actions of the events are defined within the
DnDConstants class.
public final class DnDConstants {
public static final int ACTION_COPY;
public static final int ACTION_COPY_OR_MOVE;
public static final int ACTION_LINK;
public static final int ACTION_MOVE;
public static final int ACTION_NONE;
public static final int ACTION_REFERENCE;
public DnDConstants();
}
NOTE:
In JDK 1.2beta4, this is an abstract class. However, it should be changed to an interface by the time 1.2 is released.
The component you'll drop the draggable label into is a JList.
This involves subclassing and implementing the DropTargetListener.
There are two methods of the interface that we need to implement:
dragEnter() and drop(). In dragEnter()
you need to tell the component what type of drag events you accept. Then in
drop() you accept the drop, process the dragged data, and tell
the event you're done with it. As with clipboard operations, the dragged
data is dealt with via flavors.
import java.awt.*;
import java.awt.dnd.*;
import com.sun.java.swing.*;
import java.awt.datatransfer.*;
import java.io.IOException;
import java.util.Vector;
public class DroppableList extends JList
implements DropTargetListener {
DropTarget dropTarget;
Vector v = new Vector();
public DroppableList() {
dropTarget = new DropTarget (this, this);
}
public void dragEnter (DropTargetDragEvent e){
e.acceptDrag (DnDConstants.ACTION_COPY);
}
public void dragExit (DropTargetEvent e){
}
public void dragOver (DropTargetDragEvent e){
}
public void drop (DropTargetDropEvent e){
try {
Transferable tr = e.getTransferable();
if (tr.isDataFlavorSupported (
DataFlavor.stringFlavor)) {
e.acceptDrop
(DnDConstants.ACTION_COPY_OR_MOVE);
String s = (String)tr.getTransferData (
DataFlavor.stringFlavor);
v.add (s);
setListData (v);
paintImmediately(getVisibleRect());
e.getDropTargetContext().dropComplete(true);
} else {
System.err.println ("Rejected");
e.rejectDrop();
}
} catch (IOException io) {
io.printStackTrace();
e.rejectDrop();
} catch (UnsupportedFlavorException ufe){
ufe.printStackTrace();
e.rejectDrop();
}
}
public void dropActionChanged
(DropTargetDragEvent e){
}
}
To demonstrate the droppable list and draggable label, Figure 16.2 shows a program with four labels around the list after several drag operations.
|
The test program behind Figure 16.2 is below:
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
import com.sun.java.swing.event.*;
public class Tester {
public static void main (String args[]) {
Frame f = new Frame("Tester");
DraggableLabel north = new DraggableLabel(
"One");
DraggableLabel south = new DraggableLabel(
"Two");
DraggableLabel east = new DraggableLabel(
"Three");
DraggableLabel west = new DraggableLabel(
"Four");
DroppableList list = new DroppableList();
JScrollPane pane = new JScrollPane (list);
f.add (north, BorderLayout.NORTH);
f.add (south, BorderLayout.SOUTH);
f.add (east, BorderLayout.EAST);
f.add (west, BorderLayout.WEST);
f.add (pane, BorderLayout.CENTER);
f.setSize (300, 300);
f.addWindowListener (new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setVisible (true);
}
}
Transferable interface, as well as the DataFlavor
way of dealing with the data, you should have no problem with either operation.