14.2 A Clock with Drag and Copy Support

Another way to customize Swing drag-and-drop is to subclass a Swing component, define new property accessor methods for it, and then register a TransferHandler to transfer the value of the new property. This is what we do in Example 14-2: we define a custom Swing component that displays the current time and uses a TransferHandler to make the contents of its new time property available. Like Example 14-1, this program uses a MouseMotionListener to detect drags. It also defines a key binding so that Ctrl-C copies the time to the clipboard. This example defines a custom component, but not a main( ) method: use the ShowBean program of Chapter 11 to display the component. You may want to run ShowBean again to display a JTextField or similar component, so that you have somewhere to drop or paste the time values you've dragged or copied. Also try dropping or pasting the value into other non-Java applications (such as your text editor) that you have running on your desktop.

Example 14-2 also demonstrates the javax.swing.Timer and java.text.DateFormat classes, and shows how to use the (new in Java 1.4) InputMap and ActionMap Swing classes for associating key bindings with components.

Example 14-2. DigitalClock.java
package je3.datatransfer; import javax.swing.*; import javax.swing.border.*; import java.awt.*; import java.awt.event.*; import java.awt.datatransfer.*; import javax.swing.Timer; // disambiguate from java.util.Timer import java.text.DateFormat; import java.util.Date; /**  * A custom Swing component that displays a simple digital clock.  * Demonstrates how to add copy and drag support to a Swing component  * with TransferHandler.    */ public class DigitalClock extends JLabel {     DateFormat format;   // How to display the time in string form     int updateFrequency; // How often to update the time (in milliseconds)     Timer timer;         // Triggers repeated updates to the clock          public DigitalClock( ) {         // Set default values for our properties         setFormat(DateFormat.getTimeInstance(DateFormat.MEDIUM, getLocale( )));         setUpdateFrequency(1000);  // Update once a second         // Specify a Swing TransferHandler object to do the dirty work of         // copy-and-paste and drag-and-drop for us.  This one will transfer         // the value of the "time" property.  Since this property is read-only         // it will allow drags but not drops.         setTransferHandler(new TransferHandler("time"));         // Since JLabel does not normally support drag-and-drop, we need an         // event handler to detect a drag and start the transfer.         addMouseMotionListener(new MouseMotionAdapter( ) {                 public void mouseDragged(MouseEvent e) {                     getTransferHandler( ).exportAsDrag(DigitalClock.this, e,                                                       TransferHandler.COPY);                 }             });         // Before we can have a keyboard binding for a Copy command,         // the component needs to be able to accept keyboard focus.         setFocusable(true);         // Request focus when we're clicked on         addMouseListener(new MouseAdapter( ) {                 public void mouseClicked(MouseEvent e) { requestFocus( ); }             });         // Use a LineBorder to indicate when we've got the keyboard focus         addFocusListener(new FocusListener( ) {                 public void focusGained(FocusEvent e) {                     setBorder(LineBorder.createBlackLineBorder( ));                 }                 public void focusLost(FocusEvent e) { setBorder(null); }             });         // Now bind the Ctrl-C keystroke to a "Copy" command.         InputMap im = new InputMap( );         im.setParent(getInputMap(WHEN_FOCUSED));         im.put(KeyStroke.getKeyStroke(KeyEvent.VK_C,InputEvent.CTRL_MASK),                "Copy");         setInputMap(WHEN_FOCUSED, im);                  // And bind the "Copy" command to a pre-defined Action that performs         // a copy using the TransferHandler we've installed.         ActionMap am = new ActionMap( );         am.setParent(getActionMap( ));         am.put("Copy", TransferHandler.getCopyAction( ));         setActionMap(am);         // Create a javax.swing.Timer object that will generate ActionEvents         // to tell us when to update the displayed time.  Every updateFrequency         // milliseconds, this timer will cause the actionPerformed( ) method         // to be invoked.  (For non-GUI applications, see java.util.Timer.)         timer = new Timer(updateFrequency, new ActionListener( ) {                 public void actionPerformed(ActionEvent e) {                     setText(getTime( ));  // set label to current time string                 }             });         timer.setInitialDelay(0); // Do the first update immediately         timer.start( );            // Start timing now!     }     // Return the current time as a String.     // This is the property accessor method used by the TransferHandler.     // Since there is a getter, but no setter, the TransferHandler will     // reject any attempts to drop data on us.     public String getTime( ) {         // Use the DateFormat object to convert current time to a string         return format.format(new Date( ));     }     // Here are two related property setter methods     public void setFormat(DateFormat format) { this.format = format; }     public void setUpdateFrequency(int ms) { this.updateFrequency = ms; } }

When you try out this DigitalClock component, you may notice a shortcoming: the TransferHandler class calls getTime( ) when the time value is dropped or pasted, not when it is originally dragged or copied. This is counterintuitive, but it is how TransferHandler works.



Java Examples in a Nutshell
Java Examples in a Nutshell, 3rd Edition
ISBN: 0596006209
EAN: 2147483647
Year: 2003
Pages: 285

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