Then Comes Drag and Drop

   

The Drag and Drop API is located in the java.awt.dnd package and consists of 4 interfaces and 15 classes. When you first encounter java.awt.dnd, you'll probably feel overwhelmed. After all, there's a lot of infrastructure to Drag and Drop. However, after you've learned the basics, this feeling will dissipate.

Drag and Drop uses the concepts of drag sources and drop targets. A drag source is an object associated with a component that serves as the source of a drag-and-drop operation. In contrast, a drop target is an object associated with a component that serves as the target of a drag-and-drop operation. So what gets dragged (and subsequently dropped)? It turns out that Drag and Drop uses transferables to encapsulate the data being sent from a source to a target. This data is then used by the target to perform a behind-the-scenes operation. For example, when dragging a file from one directory to another, the transferable would contain a filename. The target would use this name to identify the file being copied or moved. Figure 19.5 illustrates components , drag sources, drop targets, and transferables.

Figure 19.5. The fundamental entities of a drag-and-drop operation.

graphics/19fig05.gif

When a drag-and-drop operation is invoked, a particular action is specified. Actions determine what happens to a transferable's data when a drag-and-drop operation has completed and are represented by constants declared in the DnDConstants class. These constants (along with descriptions) are presented in Table 19.2.

Table 19.2. DnDConstants Action Constants
Action Constant Description
ACTION_COPY The drag source leaves the data intact.
ACTION_COPY_OR_MOVE The drag source performs either a copy or move action, as requested by the drop target.
ACTION_LINK A change to either the drag source or drop target is propagated to the other entity.
ACTION_MOVE The drag source deletes the data upon successful completion of the drop.
ACTION_NONE No action is taken.
ACTION_REFERENCE A synonym for ACTION_LINK.

A drag-and-drop operation is initiated with a gesture (a platform-dependent mechanism for choosing a copy, move, or link action). For example, under Windows, pressing the left mouse button would initiate a move gesture, whereas pressing this button while simultaneously pressing the Ctrl key would initiate a copy gesture.

To implement drag and drop, the first thing you do is subclass an existing component's class. For example, you might want to subclass JLabel. The following code fragment shows the result of this subclassing:

 class DragLabel extends JLabel {    DragLabel (String label, int alignment)    {       super (label, alignment);       // Other stuff    }    // More stuff } 

You would subsequently introduce a DragSource field variable and call DragSource.getDefaultDragSource to assign a reference to the default drag source that's associated with the underlying platform. This is shown in the following code fragment:

 class DragLabel extends JLabel {    private DragSource ds = DragSource.getDefaultDragSource ();    DragLabel (String label, int alignment)    {       super (label, alignment);       // Other stuff    }    // More stuff } 

At this point, you create a gesture recognizer that responds to gestures. You do this by calling DragSource 's createDefaultDragGestureRecognizer method and passing it three arguments. The first argument is a reference to the component object. (You can use the reserved word this. ) The second argument is the desired action (which you specify by using a DnDConstants constant). The final argument is a reference to an object whose class implements the DragGestureListener interface. (This interface contains a single dragGestureRecognized method, which gets called when the drag gesture recognizer detects a gesture.) The following code fragment illustrates what has been achieved thus far:

 class DragLabel extends JLabel implements DragGestureListener {    private DragSource ds = DragSource.getDefaultDragSource ();    DragLabel (String label, int alignment)    {       super (label, alignment);       int action = DnDConstants.ACTION_COPY_OR_MOVE;       ds.createDefaultDragGestureRecognizer (this,                                              action,                                              this);    }    public void dragGestureRecognized (DragGestureEvent e)    {       // ...    }    // More stuff } 

When dragGestureRecognized gets called, it sends a start dragged message to the drag source. This is accomplished by calling DragGestureEvent 's startDrag method. In turn , this method creates a DragSourceContext object to track the state of the operation by listening to a native DragSourceContextPeer. The startDrag method takes three arguments: a cursor, a transferable, and a drag source listener.

The cursor identifies the initial drag cursor and shows the preliminary state of the drag-and-drop operation. You can choose one of DragSource 's six predefined cursors , which are presented in Table 19.3.

Table 19.3. DragSource 's Predefined Cursors
Cursor Constant Description
DefaultCopyDrop The default Cursor to use with a copy operation indicating that a drop is currently allowed
DefaultCopyNoDrop The default Cursor to use with a copy operation indicating that a drop is currently not allowed
DefaultLinkDrop The default Cursor to use with a link operation indicating that a drop is currently allowed
DefaultLinkNoDrop The default Cursor to use with a link operation indicating that a drop is currently not allowed
DefaultMoveDrop The default Cursor to use with a move operation indicating that a drop is currently allowed
DefaultMoveNoDrop The default Cursor to use with a move operation indicating that a drop is currently not allowed

The transferable is an object that encapsulates data being transferred. If you recall, this object provides the data for an operation that will occur behind the scenes, after this object has been dropped.

The drag source listener provides methods , for originators of drag-and-drop operations, that are notified to track the state of a user 's gesture and to give "drag over" feedback as the drag-and-drop operation proceeds. These methods include

  • dragDropEnd

  • dragEnter

  • dragExit

  • dragOver

  • dropActionChanged

The dragDropEnd method has the following signature:

 void dragDropEnd (DragSourceDropEvent e) 

This method is called to signify that the drag-and-drop operation has completed. The DragSourceDropEvent argument's getDropSuccess method can be used to determine the termination state. Furthermore, DragSourceDropEvent 's getDropAction method returns the operation that the DropTarget selected (via the argument passed to the DropTargetDropEvent acceptDrop method) to apply to the drop operation. After this method is complete, the current DragSourceContext and associated resources become invalid.

The dragEnter method has the following signature:

 void dragEnter (DragSourceDragEvent e) 

This method is called as the drag cursor's hotspot (that portion of the cursor's icon that a windowing system uses to track the cursor ”such as the extreme tip of an arrow icon) enters a drop target. All the following conditions must be true:

  • The drag cursor's hotspot initially intersects a drop target's visible GUI component.

  • The component has an active DropTarget associated with it.

  • The DropTarget' s registered DropTargetListener dragEnter method has been invoked and returned successfully.

The dragExit method has the following signature:

 void dragExit (DragSourceEvent e) 

This method is called when the drag cursor's hotspot exits a drop target. One of the following conditions must be true:

  • The drag cursor's hotspot no longer intersects the drop target's visible GUI component.

  • The component that the drag cursor's hotspot intersected, resulting in the previous dragEnter invocation, no longer has an active DropTarget or DropTargetListener associated with it.

  • The current DropTarget 's DropTargetListener has invoked rejectDrag since the last dragEnter or dragOver invocation.

  • The drag-and-drop operation is aborted before the hotspot enters the drop target's visible component.

The dragOver method has the following signature:

 void dragOver (DragSourceDragEvent e) 

This method is called as the drag cursor's hotspot moves over a platform-dependent drop site. All the following conditions must be true:

  • The drag cursor's hotspot has moved, but still intersects the visible GUI component associated with the previous dragEnter invocation.

  • The component still has a DropTarget associated with it.

  • That DropTarget is still active.

  • The DropTarget 's registered DropTargetListener dragOver method is invoked and returns successfully.

  • The DropTarget does not reject the drag via rejectDrag.

Finally, the dropActionChanged method has the following signature:

 void dropActionChanged (DragSourceDragEvent e) 

This method is called when the user has modified the drop gesture, as when the state of the input device(s) with which the user is interacting changes. Such devices are typically the mouse buttons or keyboard modifiers.

Caution

If the startDrag method cannot initiate a drag-and-drop operation, this methods throws a java.awt.dnd.InvalidDnDOperationException object. Your code should gracefully handle this condition so a user isn't left in a confused state as to why he cannot perform a drag-and-drop operation.


After adding support for the start dragged message, the code fragment looks like the following:

 class DragLabel extends JLabel                 implements DragGestureListener, DragSourceListener {    private DragSource ds = DragSource.getDefaultDragSource ();    DragLabel (String label, int alignment)    {       super (label, alignment);       int action = DnDConstants.ACTION_COPY_OR_MOVE;       ds.createDefaultDragGestureRecognizer (this,                                              action,                                              this);    }    public void dragGestureRecognized (DragGestureEvent e)    {       try       {           Transferable t = new StringSelection (getText ());           e.startDrag (DragSource.DefaultCopyNoDrop, t, this);       }       catch (InvalidDnDOperationException e2)       {            System.out.println (e2);       }    }   public void dragDropEnd (DragSourceDropEvent e)    {       System.out.println ("Drag and drop end");       if (!e.getDropSuccess ())       {           System.out.println ("unsuccessful");           return;       }       int action = e.getDropAction ();       if ((action & DnDConstants.ACTION_MOVE) != 0)           setText ("");    }   public void dragEnter (DragSourceDragEvent e)    {       System.out.println ("Entering drop target #2");       DragSourceContext ctx = e.getDragSourceContext ();       int action = e.getDropAction ();       if ((action & DnDConstants.ACTION_COPY) != 0)           ctx.setCursor (DragSource.DefaultCopyDrop);       else           ctx.setCursor (DragSource.DefaultCopyNoDrop);    }   public void dragExit (DragSourceEvent e)    {       System.out.println ("Exiting drop target #2");    }   public void dragOver (DragSourceDragEvent e)    {       System.out.println ("Dragging over drop target #2");    }   public void dropActionChanged (DragSourceDragEvent e)    {       System.out.println ("Drop action changed #2");    } } 

After the DragLabel constructor is finished, the dragEnter method is invoked when a user moves the mouse cursor over a drop target. In response, the DragSourceContext is obtained along with the drop action. If the user has chosen to perform a copy (by simultaneously pressing the Ctrl key and left mouse button ”under Windows platforms), the DefaultCopyDrop cursor is assigned. Otherwise, the DefaultCopyNoDrop cursor is assigned. The dragOver method is called while the mouse cursor moves over the drop target. If the user should exit this target, the dragExit method is called. If the user should change the drop action (by releasing the Ctrl key), the dropActionChanged method is called. Finally, dragDropEnd is called when the drop is complete. If successful, and the action was a move action, the label's text is erased.

At this point, you're half finished. You've seen how dragging is done, but still need to see how dropping is accomplished. The component receiving a drop must be registered with a newly created DropTarget object. The DropTarget (Component c, int actions, DropTargetListener dtl) constructor creates this object and registers the component, identified by c, as the drop target. The default acceptable actions are identified by actions. Finally, a drop target listener, whose methods are called to provide drop- related notifications, is specified by dtl. The following code fragment creates a drop target that corresponds to the previously described drag source:

 new DropTarget (target, DnDConstants.ACTION_COPY_OR_MOVE, this); 

The target component is identified by target. Because the drag source is designed to initiate copy or move gestures, the target is designed to accept these gestures. This constructor also indicates that the current object (identified by this ) functions as a drop target listener.

The drop target listener provides methods for destinations of drag-and-drop operations, which are notified to track the state of a user's gesture and to give "drag under" feedback as the drag-and-drop operation proceeds. These methods include

  • dragEnter

  • dragExit

  • dragOver

  • drop

  • dropActionChanged

The dragEnter method has the following signature:

 void dragEnter (DropTargetDragEvent e) 

This method is called (prior to the drag source listener's dragEnter method) when the drag cursor's hotspot encounters a drop target.

The dragExit method has the following signature:

 void dragExit (DropTargetEvent e) 

This method is called (prior to the drag source listener's dragExit method) when the drag cursor's hotspot exits the drop target, without dropping.

The dragOver method has the following signature:

 void dragOver (DropTargetDragEvent e) 

This method is called (prior to the drag source listener's dragOver method) as the drag cursor's hotspot moves over a drop target.

The drop method has the following signature:

 void drop (DropTargetDropEvent) 

This method is called when the drag operation has terminated with a drop on this drop target. The drop method is responsible for undertaking the transfer of data associated with the gesture ”its DropTargetDropEvent argument provides a means to obtain a transferable that represents the data being transferred.

From this method, the drop target listener accepts or rejects the drop, via DropTargetDropEvent 's acceptDrop or rejectDrop methods.

Subsequent to acceptDrop (but not before), DropTargetDropEvent 's getTransferable method can be invoked and data transfer performed, via the returned transferable's getTransferData method.

At the completion of a drop, an implementation of this method is required to signal the success/failure of the drop, by passing an appropriate Boolean to DropTargetDropEvent 's dropComplete method.

To wrap up these methods, dropActionChanged has the following signature:

 void dropActionChanged (DropTargetDragEvent e) 

This method is called when the user has modified the drop gesture, as when the state of the input device(s) with which the user is interacting changes. Such devices are typically the mouse buttons or keyboard modifiers.

It's time to bring all of this together. Therefore, Listing 19.7 presents source code to the DragDropDemo application. After you spend some time studying this code, you should have a basic idea of how to incorporate drag and drop into your programs.

Listing 19.7 The DragDropDemo Application Source Code
 // DragDropDemo.java import javax.swing.*; import java.awt.*; import java.awt.datatransfer.*; import java.awt.dnd.*; import java.awt.event.*; class DragDropDemo extends JFrame                    implements ActionListener, DropTargetListener {    DragLabel source = new DragLabel ("Text", JLabel.CENTER);    JButton target = new JButton ();    DragDropDemo (String title)    {       super (title);       addWindowListener (new WindowAdapter ()                          {                              public void windowClosing (WindowEvent e)                              {                                 System.exit (0);                              }                          } );       source.setForeground (Color.red);       getContentPane ().add (source, BorderLayout.NORTH);       target.addActionListener (this);       getContentPane ().add (target, BorderLayout.SOUTH);       new DropTarget (target,                       DnDConstants.ACTION_COPY_OR_MOVE,                       this);       setSize (205, 100);       setVisible (true);    }    public void actionPerformed (ActionEvent e)    {       JButton b = (JButton) e.getSource ();       b.setText ("");       source.setText ("Text");    }    public void dragEnter (DropTargetDragEvent e)    {       System.out.println ("Entering drop target #1");    }    public void dragExit (DropTargetEvent e)    {       System.out.println ("Exiting drop target #1");    }    public void dragOver (DropTargetDragEvent e)    {       System.out.println ("Dragging over drop target #1");    }    public void drop (DropTargetDropEvent e)    {       System.out.println ("Dropping");       try       {           Transferable t = e.getTransferable ();           if (e.isDataFlavorSupported (DataFlavor.stringFlavor))           {               e.acceptDrop (e.getDropAction ());               String s;               s = (String) t.getTransferData (DataFlavor.stringFlavor);               target.setText (s);               e.dropComplete (true);           }           else               e.rejectDrop ();       }       catch (java.io.IOException e2) { }       catch (UnsupportedFlavorException e2) { }    }    public void dropActionChanged (DropTargetDragEvent e)    {       System.out.println ("Drop action changed #1");    }    public static void main (String [] args)    {       new DragDropDemo ("Drag and Drop Demo");    } } class DragLabel extends JLabel implements DragGestureListener,                                           DragSourceListener {    private DragSource ds = DragSource.getDefaultDragSource ();    public DragLabel (String s, int alignment)    {       super (s, alignment);       int action = DnDConstants.ACTION_COPY_OR_MOVE;       ds.createDefaultDragGestureRecognizer (this,                                              action,                                              this);    }   public void dragGestureRecognized (DragGestureEvent e)    {       try       {           Transferable t = new StringSelection (getText ());           e.startDrag (DragSource.DefaultCopyNoDrop, t, this);       }       catch (InvalidDnDOperationException e2)       {           System.out.println (e2);       }    }   public void dragDropEnd (DragSourceDropEvent e)    {       System.out.println ("Drag and drop end");       if (e.getDropSuccess () == false)       {           System.out.println ("unsuccessful");           return;       }       int action = e.getDropAction ();       if ((action & DnDConstants.ACTION_MOVE) != 0)           setText ("");    }   public void dragEnter (DragSourceDragEvent e)    {       System.out.println ("Entering drop target #2");       DragSourceContext ctx = e.getDragSourceContext ();       int action = e.getDropAction ();       if ((action & DnDConstants.ACTION_COPY) != 0)           ctx.setCursor (DragSource.DefaultCopyDrop);       else           ctx.setCursor (DragSource.DefaultCopyNoDrop);    }   public void dragExit (DragSourceEvent e)    {       System.out.println ("Exiting drop target #2");    }   public void dragOver (DragSourceDragEvent e)    {       System.out.println ("Dragging over drop target #2");    }   public void dropActionChanged (DragSourceDragEvent e)    {       System.out.println ("Drop action changed #2");    } } 

DragDropDemo 's GUI consists of a label and a button. The idea is to either move or copy the label's text to this button. If moved, the text disappears from the label and appears on the button. ( DragDropDemo is said to be in a moved state.) If copied, a duplicate of the label's text appears on the button. ( DragDropDemo is said to be in a copied state.) Click the button to restore DragDropDemo to its initial state.

You can track drag-and-drop operations by studying messages sent to the standard output device. Figure 19.6 shows the initial state (the top window), the moved state (the middle window), and the copied state (the bottom window).

Figure 19.6. DragDropDemo shows its three states: initial, moved, and copied.

graphics/19fig06.gif

Troubleshooting Tip

Because Drag and Drop is a rather complicated API, it's good to have a lot of examples. If you are having trouble learning this API and need some additional help, see "Learning More About Drag and Drop" in the "Troubleshooting" section at the end of this chapter.


   


Special Edition Using Java 2 Standard Edition
Special Edition Using Java 2, Standard Edition (Special Edition Using...)
ISBN: 0789724685
EAN: 2147483647
Year: 1999
Pages: 353

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net