Java/Swing JFC/Drag Drop — различия между версиями
Admin (обсуждение | вклад) м (1 версия) |
|
(нет различий)
|
Текущая версия на 09:45, 1 июня 2010
Содержание
- 1 Adding Image-Dragging Behavior
- 2 A simple drop tester application for JDK 1.4 Swing components
- 3 BasicDnD (Drag and Drop)
- 4 Built-in drag and drop support: utilize a TransferHandler class
- 5 Color Drag Source
- 6 Comma separated text will be inserted into two or more rows.
- 7 Create a drag source a drop target and a transferable object.
- 8 Demonstrate various aspects of Swing data transfer
- 9 Detect a drag initiating gesture in your application
- 10 Drag and drop
- 11 Drag and drop icons: use an icon property.
- 12 Drag and drop: TextArea
- 13 Drag capabilities: JList
- 14 Drag Color Demo
- 15 Drag Color TextField Demo
- 16 Drag Drop Tree Example
- 17 Drag File Demo
- 18 Drag List Demo
- 19 Drag Picture Demo
- 20 Drag Picture Demo 2
- 21 Dropper - show File Drop Target from Drag-n-Drop
- 22 Editor Drop Target
- 23 Editor Drop Target 2
- 24 Editor Drop Target 3
- 25 Editor Drop Target 4
- 26 Extended DnD (Drag and Drop) Demo
- 27 File Tree Drag Source
- 28 File Tree Drop Target
- 29 Getting and Setting Text on the System Clipboard
- 30 Implement drag & drop functionality in your application
- 31 implements DragGestureListener, Transferable
- 32 JLabel Drag Source
- 33 JTextArea subclass allows TransferableColor objects to
- 34 LabelDnD2 allows dropping color onto the foreground of the JLabel
- 35 Label DnD (Drag and Drop)
- 36 Making a Component Draggable
- 37 Panel Drop Target
- 38 Setting text drag in a JTextArea
- 39 Test of the DragGesture classes and JList to see if we
- 40 Transferable Color
- 41 TransferHandler subclass wraps another TransferHandler and delegates most of its operations to the wrapped handler
- 42 Use drag and drop to reorder a list
Adding Image-Dragging Behavior
<source lang="java">
import java.awt.BorderLayout; import java.awt.Container; import java.awt.Image; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.IOException; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.TransferHandler; public class DragImage {
public static void main(String args[]) { JFrame frame = new JFrame("Clip Image"); Container contentPane = frame.getContentPane(); final Clipboard clipboard = frame.getToolkit().getSystemClipboard(); Icon icon = new ImageIcon("jaeger.jpg"); final JLabel label = new JLabel(icon); label.setTransferHandler(new ImageSelection()); MouseListener mouseListener = new MouseAdapter() { public void mousePressed(MouseEvent e) { JComponent comp = (JComponent) e.getSource(); TransferHandler handler = comp.getTransferHandler(); handler.exportAsDrag(comp, e, TransferHandler.COPY); } }; label.addMouseListener(mouseListener); JScrollPane pane = new JScrollPane(label); contentPane.add(pane, BorderLayout.CENTER); JButton copy = new JButton("Copy"); copy.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { TransferHandler handler = label.getTransferHandler(); handler.exportToClipboard(label, clipboard, TransferHandler.COPY); } }); JButton clear = new JButton("Clear"); clear.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent actionEvent) { label.setIcon(null); } }); clear.setTransferHandler(new TransferHandler("text")); mouseListener = new MouseAdapter() { public void mousePressed(MouseEvent e) { JComponent comp = (JComponent) e.getSource(); TransferHandler handler = comp.getTransferHandler(); handler.exportAsDrag(comp, e, TransferHandler.COPY); } }; clear.addMouseListener(mouseListener); JButton paste = new JButton("Paste"); paste.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent actionEvent) { Transferable clipData = clipboard.getContents(clipboard); if (clipData != null) { if (clipData.isDataFlavorSupported(DataFlavor.imageFlavor)) { TransferHandler handler = label.getTransferHandler(); handler.importData(label, clipData); } } } }); JPanel p = new JPanel(); p.add(copy); p.add(clear); p.add(paste); contentPane.add(p, BorderLayout.SOUTH); JTextField tf = new JTextField(); tf.setDragEnabled(true); contentPane.add(tf, BorderLayout.NORTH); frame.setSize(300, 300); frame.show(); }
} class ImageSelection extends TransferHandler implements Transferable {
private static final DataFlavor flavors[] = { DataFlavor.imageFlavor }; private JLabel source; private Image image; public int getSourceActions(JComponent c) { return TransferHandler.COPY; } public boolean canImport(JComponent comp, DataFlavor flavor[]) { if (!(comp instanceof JLabel)) { return false; } for (int i = 0, n = flavor.length; i < n; i++) { for (int j = 0, m = flavors.length; j < m; j++) { if (flavor[i].equals(flavors[j])) { return true; } } } return false; } public Transferable createTransferable(JComponent comp) { // Clear source = null; image = null; if (comp instanceof JLabel) { JLabel label = (JLabel) comp; Icon icon = label.getIcon(); if (icon instanceof ImageIcon) { image = ((ImageIcon) icon).getImage(); source = label; return this; } } return null; } public boolean importData(JComponent comp, Transferable t) { if (comp instanceof JLabel) { JLabel label = (JLabel) comp; if (t.isDataFlavorSupported(flavors[0])) { try { image = (Image) t.getTransferData(flavors[0]); ImageIcon icon = new ImageIcon(image); label.setIcon(icon); return true; } catch (UnsupportedFlavorException ignored) { } catch (IOException ignored) { } } } return false; } // Transferable public Object getTransferData(DataFlavor flavor) { if (isDataFlavorSupported(flavor)) { return image; } return null; } public DataFlavor[] getTransferDataFlavors() { return flavors; } public boolean isDataFlavorSupported(DataFlavor flavor) { return flavor.equals(DataFlavor.imageFlavor); }
}
</source>
A simple drop tester application for JDK 1.4 Swing components
<source lang="java">
import java.awt.BorderLayout; import java.awt.Color; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextArea; public class DropTest14 extends JFrame {
JTextArea ta; public DropTest14() { super("Drop Test 1.4"); setSize(300, 300); setDefaultCloseOperation(EXIT_ON_CLOSE); getContentPane().add( new JLabel("Drop the choice from your JList here:"), BorderLayout.NORTH); ta = new JTextArea(); ta.setBackground(Color.white); getContentPane().add(ta, BorderLayout.CENTER); setVisible(true); } public static void main(String args[]) { new DropTest14(); }
}
</source>
BasicDnD (Drag and Drop)
<source lang="java">
/* From http://java.sun.ru/docs/books/tutorial/index.html */ /*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. */
/*
* BasicDnD.java is a 1.4 example that requires no other files. */
import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JColorChooser; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.ListSelectionModel; import javax.swing.table.DefaultTableModel; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeSelectionModel; public class BasicDnD extends JPanel implements ActionListener {
static JFrame frame; JTextArea textArea; JTextField textField; JList list; JTable table; JTree tree; JColorChooser colorChooser; JCheckBox toggleDnD; public BasicDnD() { super(new BorderLayout()); JPanel leftPanel = createVerticalBoxPanel(); JPanel rightPanel = createVerticalBoxPanel(); //Create a table model. DefaultTableModel tm = new DefaultTableModel(); tm.addColumn("Column 0"); tm.addColumn("Column 1"); tm.addColumn("Column 2"); tm.addColumn("Column 3"); tm .addRow(new String[] { "Table 00", "Table 01", "Table 02", "Table 03" }); tm .addRow(new String[] { "Table 10", "Table 11", "Table 12", "Table 13" }); tm .addRow(new String[] { "Table 20", "Table 21", "Table 22", "Table 23" }); tm .addRow(new String[] { "Table 30", "Table 31", "Table 32", "Table 33" }); //LEFT COLUMN //Use the table model to create a table. table = new JTable(tm); leftPanel.add(createPanelForComponent(table, "JTable")); //Create a color chooser. colorChooser = new JColorChooser(); leftPanel.add(createPanelForComponent(colorChooser, "JColorChooser")); //RIGHT COLUMN //Create a textfield. textField = new JTextField(30); textField.setText("Favorite foods:\nPizza, Moussaka, Pot roast"); rightPanel.add(createPanelForComponent(textField, "JTextField")); //Create a scrolled text area. textArea = new JTextArea(5, 30); textArea.setText("Favorite shows:\nBuffy, Alias, Angel"); JScrollPane scrollPane = new JScrollPane(textArea); rightPanel.add(createPanelForComponent(scrollPane, "JTextArea")); //Create a list model and a list. DefaultListModel listModel = new DefaultListModel(); listModel.addElement("Martha Washington"); listModel.addElement("Abigail Adams"); listModel.addElement("Martha Randolph"); listModel.addElement("Dolley Madison"); listModel.addElement("Elizabeth Monroe"); listModel.addElement("Louisa Adams"); listModel.addElement("Emily Donelson"); list = new JList(listModel); list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); JScrollPane listView = new JScrollPane(list); listView.setPreferredSize(new Dimension(300, 100)); rightPanel.add(createPanelForComponent(listView, "JList")); //Create a tree. DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode( "Mia Familia"); DefaultMutableTreeNode sharon = new DefaultMutableTreeNode("Sharon"); rootNode.add(sharon); DefaultMutableTreeNode maya = new DefaultMutableTreeNode("Maya"); sharon.add(maya); DefaultMutableTreeNode anya = new DefaultMutableTreeNode("Anya"); sharon.add(anya); sharon.add(new DefaultMutableTreeNode("Bongo")); maya.add(new DefaultMutableTreeNode("Muffin")); anya.add(new DefaultMutableTreeNode("Winky")); DefaultTreeModel model = new DefaultTreeModel(rootNode); tree = new JTree(model); tree.getSelectionModel().setSelectionMode( TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); JScrollPane treeView = new JScrollPane(tree); treeView.setPreferredSize(new Dimension(300, 100)); rightPanel.add(createPanelForComponent(treeView, "JTree")); //Create the toggle button. toggleDnD = new JCheckBox("Turn on Drag and Drop"); toggleDnD.setActionCommand("toggleDnD"); toggleDnD.addActionListener(this); JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel); splitPane.setOneTouchExpandable(true); add(splitPane, BorderLayout.CENTER); add(toggleDnD, BorderLayout.PAGE_END); setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); } protected JPanel createVerticalBoxPanel() { JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS)); p.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); return p; } public JPanel createPanelForComponent(JComponent comp, String title) { JPanel panel = new JPanel(new BorderLayout()); panel.add(comp, BorderLayout.CENTER); if (title != null) { panel.setBorder(BorderFactory.createTitledBorder(title)); } return panel; } public void actionPerformed(ActionEvent e) { if ("toggleDnD".equals(e.getActionCommand())) { boolean toggle = toggleDnD.isSelected(); textArea.setDragEnabled(toggle); textField.setDragEnabled(toggle); list.setDragEnabled(toggle); table.setDragEnabled(toggle); tree.setDragEnabled(toggle); colorChooser.setDragEnabled(toggle); } } /** * Create the GUI and show it. For thread safety, this method should be * invoked from the event-dispatching thread. */ private static void createAndShowGUI() { //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); //Create and set up the window. frame = new JFrame("BasicDnD"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the content pane. JComponent newContentPane = new BasicDnD(); newContentPane.setOpaque(true); //content panes must be opaque frame.setContentPane(newContentPane); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application"s GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); }
}
</source>
Built-in drag and drop support: utilize a TransferHandler class
<source lang="java">
import java.awt.FlowLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JTextField; import javax.swing.TransferHandler; public class SimpleDnD {
public static void main(String[] args) { JTextField field = new JTextField(10); JButton button = new JButton("Button"); JFrame f = new JFrame(); f.setTitle("Simple Drag & Drop"); f.setLayout(new FlowLayout()); f.add(button); f.add(field); field.setDragEnabled(true); button.setTransferHandler(new TransferHandler("text")); f.setSize(330, 150); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setLocationRelativeTo(null); f.setVisible(true); }
}
</source>
Color Drag Source
<source lang="java">
/*
* This example is from the book "Java Foundation Classes in a Nutshell". * Written by David Flanagan. Copyright (c) 1999 by O"Reilly & Associates. * You may distribute this source code for non-commercial purposes only. * You may study, modify, and use this example for any purpose, as long as * this notice is retained. Note that this example is provided "as is", * WITHOUT WARRANTY of any kind either expressed or implied. */
import java.awt.*; import java.awt.event.*; import java.awt.datatransfer.*; import java.awt.dnd.*; import javax.swing.*; import javax.swing.border.*; import java.io.*; /**
* This simple component displays a solid color, and allows that color * to be dragged. Also, it copies the color to the clipboard when the * user clicks on it. */
public class ColorSource extends JComponent
implements ClipboardOwner, DragGestureListener, DragSourceListener
{
Color color; // The color to display TransferableColor tcolor; // The color, encapsulated for data transfer DragSource dragSource; // We need this object for drag-and-drop /** A ColorSource normally displays itself with this border */ protected static Border defaultBorder = new BevelBorder(BevelBorder.LOWERED); /** When we are the clipboard owner, uses this border */ protected static Border highlightBorder = new CompoundBorder(defaultBorder, new LineBorder(Color.black, 2)); /** Create a new ColorSource object that displays the speciifed color */ public ColorSource(Color color) { // Save the color. Encapsulate it in a Transferable object so that // it can be used with cut-and-paste and drag-and-drop this.color = color; this.tcolor = new TransferableColor(color); // Set our default border this.setBorder(defaultBorder); // Listen for mouse clicks, and copy the color to the clipboard. this.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { copy(); } }); // Set up a DragGestureRecognizer that will detect when the user // begins a drag. When it detects one, it will notify us by calling // the dragGestureRecognized() method of the DragGestureListener // interface we implement below this.dragSource = DragSource.getDefaultDragSource(); dragSource.createDefaultDragGestureRecognizer(this, // Look for drags on us DnDConstants.ACTION_COPY_OR_MOVE, // Recognize these types this); // Tell us when recognized } // These are component methods that make this class work as a component. // They specify how big the component is, and what it it looks like. protected static Dimension mysize = new Dimension(25, 25); public Dimension getMinimumSize() { return mysize; } public Dimension getPreferredSize() { return mysize; } public void paintComponent(Graphics g) { g.setColor(color); Dimension s = this.getSize(); Insets i = this.getInsets(); g.fillRect(i.left, i.top, s.width-i.left-i.right, s.height-i.top-i.bottom); } // The methods below support cut-and-paste /** This method copies the color to the clipboard. */ public void copy() { // Get system clipboard Clipboard c = this.getToolkit().getSystemClipboard(); // Put our TransferableColor object on the clipboard. // Also, we"ll get notification when we no longer own the clipboard c.setContents(tcolor, this); // Set a special border on ourselves that indicates that we"re the // current color available for pasting. this.setBorder(highlightBorder); } // This ClipboardOwner method is called when something else is // placed on the clipboard. It means that our color is no longer // available for pasting, and we should not display the highlight border public void lostOwnership(Clipboard clipboard, Transferable contents) { this.setBorder(defaultBorder); } // The methods below support drag-and-drop // This DragGestureListener method is called when the DragGestureRecognizer // detects that the user has dragged the mouse. It is responsible // for beginning the drag-and-drop process. public void dragGestureRecognized(DragGestureEvent e) { // Create an image we can drag along with us. // Not all systems support this, but it doesn"t hurt to try. Image colorblock = this.createImage(25,25); Graphics g = colorblock.getGraphics(); g.setColor(color); g.fillRect(0,0,25,25); // Start dragging our transferable color object. e.startDrag(DragSource.DefaultMoveDrop, // The initial drag cursor colorblock, new Point(0,0), // The image to drag tcolor, // The data being dragged this); // Who to notify during drag } // These methods implement DragSourceListener. // Since we passed this object to startDrag, these methods will be // called at interesting points during the drag. We could use them, // for example to implement custom cursors or other "drag over" effects public void dragEnter(DragSourceDragEvent e) {} public void dragExit(DragSourceEvent e) {} public void dragDropEnd(DragSourceDropEvent e) {} public void dragOver(DragSourceDragEvent e) {} public void dropActionChanged(DragSourceDragEvent e) {}
}
</source>
Comma separated text will be inserted into two or more rows.
<source lang="java">
import java.awt.FlowLayout; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import javax.swing.DefaultListModel; import javax.swing.DropMode; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.TransferHandler; public class ListDrop {
class ListHandler extends TransferHandler { public boolean canImport(TransferSupport support) { if (!support.isDrop()) { return false; } return support.isDataFlavorSupported(DataFlavor.stringFlavor); } public boolean importData(TransferSupport support) { if (!canImport(support)) { return false; } Transferable transferable = support.getTransferable(); String line; try { line = (String) transferable.getTransferData(DataFlavor.stringFlavor); } catch (Exception e) { return false; } JList.DropLocation dl = (JList.DropLocation) support.getDropLocation(); int index = dl.getIndex(); model.add(index++, line); return true; } } JTextField field = new JTextField(20); DefaultListModel model = new DefaultListModel(); public ListDrop() { JFrame f = new JFrame(); JList list = new JList(model); list.setDropMode(DropMode.INSERT); list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); list.setTransferHandler(new ListHandler()); field.setDragEnabled(true); f.setLayout(new FlowLayout()); f.add(new JScrollPane(list)); f.add(field); f.pack(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); } public static void main(String[] args) { new ListDrop(); }
}
</source>
Create a drag source a drop target and a transferable object.
<source lang="java">
import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetAdapter; import java.awt.dnd.DropTargetDropEvent; import javax.swing.JFrame; import javax.swing.JPanel; public class ComplexExample extends JFrame implements DragGestureListener {
public ComplexExample() { JPanel left = new JPanel(); left.setBackground(Color.red); JPanel right = new JPanel(); right.setBackground(Color.white); new MyDropTargetListener(right); DragSource ds = new DragSource(); ds.createDefaultDragGestureRecognizer(left, DnDConstants.ACTION_COPY, this); setLayout(new FlowLayout()); add(left); add(right); setSize(40,50); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); setVisible(true); } public void dragGestureRecognized(DragGestureEvent event) { Cursor cursor = null; JPanel panel = (JPanel) event.getComponent(); Color color = panel.getBackground(); if (event.getDragAction() == DnDConstants.ACTION_COPY) { cursor = DragSource.DefaultCopyDrop; } event.startDrag(cursor, new TransferableColor(color)); } class MyDropTargetListener extends DropTargetAdapter { private DropTarget dropTarget; private JPanel panel; public MyDropTargetListener(JPanel panel) { this.panel = panel; dropTarget = new DropTarget(panel, DnDConstants.ACTION_COPY, this, true, null); } public void drop(DropTargetDropEvent event) { try { Transferable tr = event.getTransferable(); Color color = (Color) tr.getTransferData(TransferableColor.colorFlavor); if (event.isDataFlavorSupported(TransferableColor.colorFlavor)) { event.acceptDrop(DnDConstants.ACTION_COPY); this.panel.setBackground(color); event.dropComplete(true); return; } event.rejectDrop(); } catch (Exception e) { e.printStackTrace(); event.rejectDrop(); } } } public static void main(String[] args) { new ComplexExample(); }
} class TransferableColor implements Transferable {
protected static DataFlavor colorFlavor = new DataFlavor(Color.class, "A Color Object"); protected static DataFlavor[] supportedFlavors = { colorFlavor }; Color color; public TransferableColor(Color color) { this.color = color; } public DataFlavor[] getTransferDataFlavors() { return supportedFlavors; } public boolean isDataFlavorSupported(DataFlavor flavor) { if (flavor.equals(colorFlavor) || flavor.equals(DataFlavor.stringFlavor)) return true; return false; } public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { if (flavor.equals(colorFlavor)) return color; else if (flavor.equals(DataFlavor.stringFlavor)) return color.toString(); else throw new UnsupportedFlavorException(flavor); }
}
</source>
Demonstrate various aspects of Swing data transfer
<source lang="java">
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002. * All rights reserved. Software written by Ian F. Darwin and others. * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS"" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s, * pioneering role in inventing and promulgating (and standardizing) the Java * language and environment is gratefully acknowledged. * * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for * inventing predecessor languages C and C++ is also gratefully acknowledged. */
import java.awt.Color; import java.awt.Container; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.TransferHandler; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /**
* Demonstrate various aspects of Swing "data transfer". * * @author Ian Darwin, http://www.darwinsys.ru * @author Jonathan Fuerth, http://www.SQLPower.ca */
public class Transfer extends JFrame {
public static void main(String[] args) { new Transfer().setVisible(true); } private JTextField tf; private JLabel l; private JComboBox propertyComboBox; public Transfer() { // Establish the GUI Container cp = new Box(BoxLayout.X_AXIS); setContentPane(cp); JPanel firstPanel = new JPanel(); propertyComboBox = new JComboBox(); propertyComboBox.addItem("text"); propertyComboBox.addItem("font"); propertyComboBox.addItem("background"); propertyComboBox.addItem("foreground"); firstPanel.add(propertyComboBox); cp.add(firstPanel); cp.add(Box.createGlue()); tf = new JTextField("Hello"); tf.setForeground(Color.RED); tf.setDragEnabled(true); cp.add(tf); cp.add(Box.createGlue()); l = new JLabel("Hello"); l.setBackground(Color.YELLOW); cp.add(l); cp.add(Box.createGlue()); JSlider stryder = new JSlider(SwingConstants.VERTICAL); stryder.setMinimum(10); stryder.setValue(14); stryder.setMaximum(72); stryder.setMajorTickSpacing(10); stryder.setPaintTicks(true); cp.add(stryder); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(500, 300); // Add Listeners and Converters setMyTransferHandlers((String) propertyComboBox.getSelectedItem()); // Mousing in the Label starts a Drag. MouseListener myDragListener = new MouseAdapter() { public void mousePressed(MouseEvent e) { JComponent c = (JComponent) e.getSource(); TransferHandler handler = c.getTransferHandler(); handler.exportAsDrag(c, e, TransferHandler.COPY); } }; l.addMouseListener(myDragListener); // Selecting in the ComboBox makes that the property that is xfered. propertyComboBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ce) { JComboBox bx = (JComboBox) ce.getSource(); String prop = (String) bx.getSelectedItem(); setMyTransferHandlers(prop); } }); // Typing a word and pressing enter in the TextField tries // to set that as the font name. tf.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { JTextField jtf = (JTextField) evt.getSource(); String fontName = jtf.getText(); Font font = new Font(fontName, Font.BOLD, 18); tf.setFont(font); } }); // Setting the Slider sets that font into the textfield. stryder.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent evt) { JSlider sl = (JSlider) evt.getSource(); Font oldf = tf.getFont(); Font newf = oldf.deriveFont((float) sl.getValue()); tf.setFont(newf); } }); } private void setMyTransferHandlers(String s) { TransferHandler th = new TransferHandler(s); tf.setTransferHandler(th); l.setTransferHandler(th); }
}
</source>
Detect a drag initiating gesture in your application
<source lang="java">
import java.awt.BorderLayout; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragGestureRecognizer; import java.awt.dnd.DragSource; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; public class Main extends JFrame implements DragGestureListener {
String[] items = { "Java", "C", "C++", "Lisp", "Perl", "Python" }; DragSource ds = new DragSource(); JList jl = new JList(items); public Main() { setSize(200, 150); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); getContentPane().add(new JScrollPane(jl), BorderLayout.CENTER); DragGestureRecognizer dgr = ds.createDefaultDragGestureRecognizer(jl, DnDConstants.ACTION_COPY, this); setVisible(true); } public void dragGestureRecognized(DragGestureEvent dge) { System.out.println("Drag Gesture Recognized!"); } public static void main(String args[]) { new Main(); }
}
</source>
Drag and drop
<source lang="java">
/*
* Copyright (c) 2000 David Flanagan. All rights reserved. * This code is from the book Java Examples in a Nutshell, 2nd Edition. * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied. * You may study, use, and modify it for any non-commercial purpose. * You may distribute it non-commercially as long as you retain this notice. * For a commercial use license, or to purchase the book (recommended), * visit http://www.davidflanagan.ru/javaexamples2. */
import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.Shape; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.Serializable; import java.util.ArrayList; import java.util.StringTokenizer; import javax.swing.ButtonGroup; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JToggleButton; import javax.swing.JToolBar; import javax.swing.border.BevelBorder; import javax.swing.border.Border; /**
* This component can operate in two modes. In "draw mode", it allows the user * to scribble with the mouse. In "drag mode", it allows the user to drag * scribbles with the mouse. Regardless of the mode, it always allows scribbles * to be dropped on it from other applications. */
public class ScribbleDragAndDrop extends JComponent implements
DragGestureListener, // For recognizing the start of drags DragSourceListener, // For processing drag source events DropTargetListener, // For processing drop target events MouseListener, // For processing mouse clicks MouseMotionListener // For processing mouse drags
{
ArrayList scribbles = new ArrayList(); // A list of Scribbles to draw Scribble currentScribble; // The scribble in progress Scribble beingDragged; // The scribble being dragged DragSource dragSource; // A central DnD object boolean dragMode; // Are we dragging or scribbling? // These are some constants we use static final int LINEWIDTH = 3; static final BasicStroke linestyle = new BasicStroke(LINEWIDTH); static final Border normalBorder = new BevelBorder(BevelBorder.LOWERED); static final Border dropBorder = new BevelBorder(BevelBorder.RAISED); /** The constructor: set up drag-and-drop stuff */ public ScribbleDragAndDrop() { // Give ourselves a nice default border. // We"ll change this border during drag-and-drop. setBorder(normalBorder); // Register listeners to handle drawing addMouseListener(this); addMouseMotionListener(this); // Create a DragSource and DragGestureRecognizer to listen for drags // The DragGestureRecognizer will notify the DragGestureListener // when the user tries to drag an object dragSource = DragSource.getDefaultDragSource(); dragSource.createDefaultDragGestureRecognizer(this, // What component DnDConstants.ACTION_COPY_OR_MOVE, // What drag types? this);// the listener // Create and set up a DropTarget that will listen for drags and // drops over this component, and will notify the DropTargetListener DropTarget dropTarget = new DropTarget(this, // component to monitor this); // listener to notify this.setDropTarget(dropTarget); // Tell the component about it. } /** * The component draws itself by drawing each of the Scribble objects. */ public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; g2.setStroke(linestyle); // Specify wide lines int numScribbles = scribbles.size(); for (int i = 0; i < numScribbles; i++) { Scribble s = (Scribble) scribbles.get(i); g2.draw(s); // Draw the scribble } } public void setDragMode(boolean dragMode) { this.dragMode = dragMode; } public boolean getDragMode() { return dragMode; } /** * This method, and the following four methods are from the MouseListener * interface. If we"re in drawing mode, this method handles mouse down * events and starts a new scribble. */ public void mousePressed(MouseEvent e) { if (dragMode) return; currentScribble = new Scribble(); scribbles.add(currentScribble); currentScribble.moveto(e.getX(), e.getY()); } public void mouseReleased(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } /** * This method and mouseMoved() below are from the MouseMotionListener * interface. If we"re in drawing mode, this method adds a new point to the * current scribble and requests a redraw */ public void mouseDragged(MouseEvent e) { if (dragMode) return; currentScribble.lineto(e.getX(), e.getY()); repaint(); } public void mouseMoved(MouseEvent e) { } /** * This method implements the DragGestureListener interface. It will be * invoked when the DragGestureRecognizer thinks that the user has initiated * a drag. If we"re not in drawing mode, then this method will try to figure * out which Scribble object is being dragged, and will initiate a drag on * that object. */ public void dragGestureRecognized(DragGestureEvent e) { // Don"t drag if we"re not in drag mode if (!dragMode) return; // Figure out where the drag started MouseEvent inputEvent = (MouseEvent) e.getTriggerEvent(); int x = inputEvent.getX(); int y = inputEvent.getY(); // Figure out which scribble was clicked on, if any by creating a // small rectangle around the point and testing for intersection. Rectangle r = new Rectangle(x - LINEWIDTH, y - LINEWIDTH, LINEWIDTH * 2, LINEWIDTH * 2); int numScribbles = scribbles.size(); for (int i = 0; i < numScribbles; i++) { // Loop through the scribbles Scribble s = (Scribble) scribbles.get(i); if (s.intersects(r)) { // The user started the drag on top of this scribble, so // start to drag it. // First, remember which scribble is being dragged, so we can // delete it later (if this is a move rather than a copy) beingDragged = s; // Next, create a copy that will be the one dragged Scribble dragScribble = (Scribble) s.clone(); // Adjust the origin to the point the user clicked on. dragScribble.translate(-x, -y); // Choose a cursor based on the type of drag the user initiated Cursor cursor; switch (e.getDragAction()) { case DnDConstants.ACTION_COPY: cursor = DragSource.DefaultCopyDrop; break; case DnDConstants.ACTION_MOVE: cursor = DragSource.DefaultMoveDrop; break; default: return; // We only support move and copys } // Some systems allow us to drag an image along with the // cursor. If so, create an image of the scribble to drag if (dragSource.isDragImageSupported()) { Rectangle scribbleBox = dragScribble.getBounds(); Image dragImage = this.createImage(scribbleBox.width, scribbleBox.height); Graphics2D g = (Graphics2D) dragImage.getGraphics(); g.setColor(new Color(0, 0, 0, 0)); // transparent background g.fillRect(0, 0, scribbleBox.width, scribbleBox.height); g.setColor(Color.black); g.setStroke(linestyle); g.translate(-scribbleBox.x, -scribbleBox.y); g.draw(dragScribble); Point hotspot = new Point(-scribbleBox.x, -scribbleBox.y); // Now start dragging, using the image. e.startDrag(cursor, dragImage, hotspot, dragScribble, this); } else { // Or start the drag without an image e.startDrag(cursor, dragScribble, this); } // After we"ve started dragging one scribble, stop looking return; } } } /** * This method, and the four unused methods that follow it implement the * DragSourceListener interface. dragDropEnd() is invoked when the user * drops the scribble she was dragging. If the drop was successful, and if * the user did a "move" rather than a "copy", then we delete the dragged * scribble from the list of scribbles to draw. */ public void dragDropEnd(DragSourceDropEvent e) { if (!e.getDropSuccess()) return; int action = e.getDropAction(); if (action == DnDConstants.ACTION_MOVE) { scribbles.remove(beingDragged); beingDragged = null; repaint(); } } // These methods are also part of DragSourceListener. // They are invoked at interesting points during the drag, and can be // used to perform "drag over" effects, such as changing the drag cursor // or drag image. public void dragEnter(DragSourceDragEvent e) { } public void dragExit(DragSourceEvent e) { } public void dropActionChanged(DragSourceDragEvent e) { } public void dragOver(DragSourceDragEvent e) { } // The next five methods implement DropTargetListener /** * This method is invoked when the user first drags something over us. If we * understand the data type being dragged, then call acceptDrag() to tell * the system that we"re receptive. Also, we change our border as a "drag * under" effect to signal that we can accept the drop. */ public void dragEnter(DropTargetDragEvent e) { if (e.isDataFlavorSupported(Scribble.scribbleDataFlavor) || e.isDataFlavorSupported(DataFlavor.stringFlavor)) { e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE); this.setBorder(dropBorder); } } /** The user is no longer dragging over us, so restore the border */ public void dragExit(DropTargetEvent e) { this.setBorder(normalBorder); } /** * This is the key method of DropTargetListener. It is invoked when the user * drops something on us. */ public void drop(DropTargetDropEvent e) { this.setBorder(normalBorder); // Restore the default border // First, check whether we understand the data that was dropped. // If we supports our data flavors, accept the drop, otherwise reject. if (e.isDataFlavorSupported(Scribble.scribbleDataFlavor) || e.isDataFlavorSupported(DataFlavor.stringFlavor)) { e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); } else { e.rejectDrop(); return; } // We"ve accepted the drop, so now we attempt to get the dropped data // from the Transferable object. Transferable t = e.getTransferable(); // Holds the dropped data Scribble droppedScribble; // This will hold the Scribble object // First, try to get the data directly as a scribble object try { droppedScribble = (Scribble) t .getTransferData(Scribble.scribbleDataFlavor); } catch (Exception ex) { // unsupported flavor, IO exception, etc. // If that doesn"t work, try to get it as a String and parse it try { String s = (String) t.getTransferData(DataFlavor.stringFlavor); droppedScribble = Scribble.parse(s); } catch (Exception ex2) { // If we still couldn"t get the data, tell the system we failed e.dropComplete(false); return; } } // If we get here, we"ve got the Scribble object Point p = e.getLocation(); // Where did the drop happen? droppedScribble.translate(p.getX(), p.getY()); // Move it there scribbles.add(droppedScribble); // add to display list repaint(); // ask for redraw e.dropComplete(true); // signal success! } // These are unused DropTargetListener methods public void dragOver(DropTargetDragEvent e) { } public void dropActionChanged(DropTargetDragEvent e) { } /** * The main method. Creates a simple application using this class. Note the * buttons for switching between draw mode and drag mode. */ public static void main(String[] args) { // Create a frame and put a scribble pane in it JFrame frame = new JFrame("ScribbleDragAndDrop"); final ScribbleDragAndDrop scribblePane = new ScribbleDragAndDrop(); frame.getContentPane().add(scribblePane, BorderLayout.CENTER); // Create two buttons for switching modes JToolBar toolbar = new JToolBar(); ButtonGroup group = new ButtonGroup(); JToggleButton draw = new JToggleButton("Draw"); JToggleButton drag = new JToggleButton("Drag"); draw.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { scribblePane.setDragMode(false); } }); drag.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { scribblePane.setDragMode(true); } }); group.add(draw); group.add(drag); toolbar.add(draw); toolbar.add(drag); frame.getContentPane().add(toolbar, BorderLayout.NORTH); // Start off in drawing mode draw.setSelected(true); scribblePane.setDragMode(false); // Pop up the window frame.setSize(400, 400); frame.setVisible(true); }
} class Scribble implements Shape, Transferable, Serializable, Cloneable {
protected double[] points = new double[64]; // The scribble data protected int numPoints = 0; // The current number of points double maxX = Double.NEGATIVE_INFINITY; // The bounding box double maxY = Double.NEGATIVE_INFINITY; double minX = Double.POSITIVE_INFINITY; double minY = Double.POSITIVE_INFINITY; /** * Begin a new polyline at (x,y). Note the use of Double.NaN in the points * array to mark the beginning of a new polyline */ public void moveto(double x, double y) { if (numPoints + 3 > points.length) reallocate(); // Mark this as the beginning of a new line points[numPoints++] = Double.NaN; // The rest of this method is just like lineto(); lineto(x, y); } /** * Add the point (x,y) to the end of the current polyline */ public void lineto(double x, double y) { if (numPoints + 2 > points.length) reallocate(); points[numPoints++] = x; points[numPoints++] = y; // See if the point enlarges our bounding box if (x > maxX) maxX = x; if (x < minX) minX = x; if (y > maxY) maxY = y; if (y < minY) minY = y; } /** * Append the Scribble s to this Scribble */ public void append(Scribble s) { int n = numPoints + s.numPoints; double[] newpoints = new double[n]; System.arraycopy(points, 0, newpoints, 0, numPoints); System.arraycopy(s.points, 0, newpoints, numPoints, s.numPoints); points = newpoints; numPoints = n; minX = Math.min(minX, s.minX); maxX = Math.max(maxX, s.maxX); minY = Math.min(minY, s.minY); maxY = Math.max(maxY, s.maxY); } /** * Translate the coordinates of all points in the Scribble by x,y */ public void translate(double x, double y) { for (int i = 0; i < numPoints; i++) { if (Double.isNaN(points[i])) continue; points[i++] += x; points[i] += y; } minX += x; maxX += x; minY += y; maxY += y; } /** An internal method to make more room in the data array */ protected void reallocate() { double[] newpoints = new double[points.length * 2]; System.arraycopy(points, 0, newpoints, 0, numPoints); points = newpoints; } /** Clone a Scribble object and its internal array of data */ public Object clone() { try { Scribble s = (Scribble) super.clone(); // make a copy of all fields s.points = (double[]) points.clone(); // copy the entire array return s; } catch (CloneNotSupportedException e) { // This should never happen return this; } } /** Convert the scribble data to a textual format */ public String toString() { StringBuffer b = new StringBuffer(); for (int i = 0; i < numPoints; i++) { if (Double.isNaN(points[i])) { b.append("m "); } else { b.append(points[i]); b.append(" "); } } return b.toString(); } /** * Create a new Scribble object and initialize it by parsing a string of * coordinate data in the format produced by toString() */ public static Scribble parse(String s) throws NumberFormatException { StringTokenizer st = new StringTokenizer(s); Scribble scribble = new Scribble(); while (st.hasMoreTokens()) { String t = st.nextToken(); if (t.charAt(0) == "m") { scribble.moveto(Double.parseDouble(st.nextToken()), Double .parseDouble(st.nextToken())); } else { scribble.lineto(Double.parseDouble(t), Double.parseDouble(st .nextToken())); } } return scribble; } // ========= The following methods implement the Shape interface ======== /** Return the bounding box of the Shape */ public Rectangle getBounds() { return new Rectangle((int) (minX - 0.5f), (int) (minY - 0.5f), (int) (maxX - minX + 0.5f), (int) (maxY - minY + 0.5f)); } /** Return the bounding box of the Shape */ public Rectangle2D getBounds2D() { return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY); } /** Our shape is an open curve, so it never contains anything */ public boolean contains(Point2D p) { return false; } public boolean contains(Rectangle2D r) { return false; } public boolean contains(double x, double y) { return false; } public boolean contains(double x, double y, double w, double h) { return false; } /** * Determine if the scribble intersects the specified rectangle by testing * each line segment individually */ public boolean intersects(Rectangle2D r) { if (numPoints < 4) return false; int i = 0; double x1, y1, x2 = 0.0, y2 = 0.0; while (i < numPoints) { if (Double.isNaN(points[i])) { // If we"re beginning a new line i++; // Skip the NaN x2 = points[i++]; y2 = points[i++]; } else { x1 = x2; y1 = y2; x2 = points[i++]; y2 = points[i++]; if (r.intersectsLine(x1, y1, x2, y2)) return true; } } return false; } /** Test for intersection by invoking the method above */ public boolean intersects(double x, double y, double w, double h) { return intersects(new Rectangle2D.Double(x, y, w, h)); } /** * Return a PathIterator object that tells Java2D how to draw this scribble */ public PathIterator getPathIterator(AffineTransform at) { return new ScribbleIterator(at); } /** * Return a PathIterator that doesn"t include curves. Ours never does. */ public PathIterator getPathIterator(AffineTransform at, double flatness) { return getPathIterator(at); } /** * This inner class implements the PathIterator interface to describe the * shape of a scribble. Since a Scribble is composed of arbitrary movetos * and linetos, we simply return their coordinates */ public class ScribbleIterator implements PathIterator { protected int i = 0; // Position in array protected AffineTransform transform; public ScribbleIterator(AffineTransform transform) { this.transform = transform; } /** How to determine insideness and outsideness for this shape */ public int getWindingRule() { return PathIterator.WIND_NON_ZERO; } /** Have we reached the end of the scribble path yet? */ public boolean isDone() { return i >= numPoints; } /** Move on to the next segment of the path */ public void next() { if (Double.isNaN(points[i])) i += 3; else i += 2; } /** * Get the coordinates of the current moveto or lineto as floats */ public int currentSegment(float[] coords) { int retval; if (Double.isNaN(points[i])) { // If its a moveto coords[0] = (float) points[i + 1]; coords[1] = (float) points[i + 2]; retval = SEG_MOVETO; } else { coords[0] = (float) points[i]; coords[1] = (float) points[i + 1]; retval = SEG_LINETO; } // If a transform was specified, use it on the coordinates if (transform != null) transform.transform(coords, 0, coords, 0, 1); return retval; } /** * Get the coordinates of the current moveto or lineto as doubles */ public int currentSegment(double[] coords) { int retval; if (Double.isNaN(points[i])) { coords[0] = points[i + 1]; coords[1] = points[i + 2]; retval = SEG_MOVETO; } else { coords[0] = points[i]; coords[1] = points[i + 1]; retval = SEG_LINETO; } if (transform != null) transform.transform(coords, 0, coords, 0, 1); return retval; } } //====== The following methods implement the Transferable interface ===== // This is the custom DataFlavor for Scribble objects public static DataFlavor scribbleDataFlavor = new DataFlavor( Scribble.class, "Scribble"); // This is a list of the flavors we know how to work with public static DataFlavor[] supportedFlavors = { scribbleDataFlavor, DataFlavor.stringFlavor }; /** Return the data formats or "flavors" we know how to transfer */ public DataFlavor[] getTransferDataFlavors() { return (DataFlavor[]) supportedFlavors.clone(); } /** Check whether we support a given flavor */ public boolean isDataFlavorSupported(DataFlavor flavor) { return (flavor.equals(scribbleDataFlavor) || flavor .equals(DataFlavor.stringFlavor)); } /** * Return the scribble data in the requested format, or throw an exception * if we don"t support the requested format */ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { if (flavor.equals(scribbleDataFlavor)) { return this; } else if (flavor.equals(DataFlavor.stringFlavor)) { return toString(); } else throw new UnsupportedFlavorException(flavor); }
}
</source>
Drag and drop icons: use an icon property.
<source lang="java">
import java.awt.FlowLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.TransferHandler; class DragMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent e) { JComponent c = (JComponent) e.getSource(); TransferHandler handler = c.getTransferHandler(); handler.exportAsDrag(c, e, TransferHandler.COPY); }
} public class IconDnD {
public static void main(String[] args) { JFrame f = new JFrame("Icon Drag & Drop"); ImageIcon icon1 = new ImageIcon("a.png"); ImageIcon icon2 = new ImageIcon("b.png"); ImageIcon icon3 = new ImageIcon("c.png"); JButton button = new JButton(icon2); JLabel label1 = new JLabel(icon1, JLabel.CENTER); JLabel label2 = new JLabel(icon3, JLabel.CENTER); MouseListener listener = new DragMouseAdapter(); label1.addMouseListener(listener); label2.addMouseListener(listener); label1.setTransferHandler(new TransferHandler("icon")); button.setTransferHandler(new TransferHandler("icon")); label2.setTransferHandler(new TransferHandler("icon")); f.setLayout(new FlowLayout()); f.add(label1); f.add(button); f.add(label2); f.pack(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); }
}
</source>
Drag and drop: TextArea
<source lang="java">
/* Java Swing, 2nd Edition By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole ISBN: 0-596-00408-7 Publisher: O"Reilly
- /
// DropTest2.java //Another simple drag & drop tester application. // import java.awt.BorderLayout; import java.awt.Color; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.io.InputStream; import java.io.InputStreamReader; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextArea; public class DropTest2 extends JFrame implements DropTargetListener {
DropTarget dt; JTextArea ta; public DropTest2() { super("Drop Test"); setSize(300, 300);
getContentPane().add( new JLabel("Drop a list from your file chooser here:"), BorderLayout.NORTH); ta = new JTextArea(); ta.setBackground(Color.white); getContentPane().add(ta, BorderLayout.CENTER); // Set up our text area to recieve drops... // This class will handle drop events dt = new DropTarget(ta, this); setVisible(true); } public void dragEnter(DropTargetDragEvent dtde) { System.out.println("Drag Enter"); } public void dragExit(DropTargetEvent dte) { System.out.println("Drag Exit"); } public void dragOver(DropTargetDragEvent dtde) { System.out.println("Drag Over"); } public void dropActionChanged(DropTargetDragEvent dtde) { System.out.println("Drop Action Changed"); } public void drop(DropTargetDropEvent dtde) { try { // Ok, get the dropped object and try to figure out what it is Transferable tr = dtde.getTransferable(); DataFlavor[] flavors = tr.getTransferDataFlavors(); for (int i = 0; i < flavors.length; i++) { System.out.println("Possible flavor: " + flavors[i].getMimeType()); // Check for file lists specifically if (flavors[i].isFlavorJavaFileListType()) { // Great! Accept copy drops... dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); ta.setText("Successful file list drop.\n\n"); // And add the list of file names to our text area java.util.List list = (java.util.List) tr .getTransferData(flavors[i]); for (int j = 0; j < list.size(); j++) { ta.append(list.get(j) + "\n"); } // If we made it this far, everything worked. dtde.dropComplete(true); return; } // Ok, is it another Java object? else if (flavors[i].isFlavorSerializedObjectType()) { dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); ta.setText("Successful text drop.\n\n"); Object o = tr.getTransferData(flavors[i]); ta.append("Object: " + o); dtde.dropComplete(true); return; } // How about an input stream? else if (flavors[i].isRepresentationClassInputStream()) { dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); ta.setText("Successful text drop.\n\n"); ta.read(new InputStreamReader((InputStream) tr .getTransferData(flavors[i])), "from system clipboard"); dtde.dropComplete(true); return; } } // Hmm, the user must not have dropped a file list System.out.println("Drop failed: " + dtde); dtde.rejectDrop(); } catch (Exception e) { e.printStackTrace(); dtde.rejectDrop(); } } public static void main(String args[]) { new DropTest2(); }
}
</source>
Drag capabilities: JList
<source lang="java">
import java.awt.BorderLayout; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; public class DragTest14 extends JFrame {
JList jl; String[] items = { "Java", "C", "C++", "Lisp", "Perl", "Python" }; public DragTest14() { super("Drag Test 1.4"); setSize(200, 150); setDefaultCloseOperation(EXIT_ON_CLOSE); jl = new JList(items); jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); jl.setDragEnabled(true); getContentPane().add(new JScrollPane(jl), BorderLayout.CENTER); setVisible(true); } public static void main(String args[]) { new DragTest14(); }
}
</source>
Drag Color Demo
<source lang="java">
/* From http://java.sun.ru/docs/books/tutorial/index.html */ /*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. */
/*
* DragColorDemo.java is a 1.4 example that requires * the following file: * ColorTransferHandler.java */
import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridLayout; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JColorChooser; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.TransferHandler; /**
* Example code that shows any JComponent can be customized to allow dropping of * a color. */
public class DragColorDemo extends JPanel implements ActionListener {
JCheckBox toggleForeground; ColorTransferHandler colorHandler; public DragColorDemo() { super(new BorderLayout()); setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); JColorChooser chooser = new JColorChooser(); chooser.setDragEnabled(true); add(chooser, BorderLayout.PAGE_START); //Create the color transfer handler. colorHandler = new ColorTransferHandler(); //Create a matrix of 9 buttons. JPanel buttonPanel = new JPanel(new GridLayout(3, 3)); for (int i = 0; i < 9; i++) { JButton tmp = new JButton("Button " + i); tmp.setTransferHandler(colorHandler); buttonPanel.add(tmp); } add(buttonPanel, BorderLayout.CENTER); //Create a check box. toggleForeground = new JCheckBox("Change the foreground color."); toggleForeground.setSelected(true); toggleForeground.addActionListener(this); JPanel textPanel = new JPanel(new BorderLayout()); textPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); textPanel.add(toggleForeground, BorderLayout.PAGE_START); //Create a label. JLabel label = new JLabel( "Change the color of any button or this label by dropping a color."); label.setTransferHandler(colorHandler); label.setOpaque(true); //So the background color can be changed. textPanel.add(label, BorderLayout.PAGE_END); add(textPanel, BorderLayout.PAGE_END); } public void actionPerformed(ActionEvent e) { colorHandler.setChangesForegroundColor(toggleForeground.isSelected()); } /** * Create the GUI and show it. For thread safety, this method should be * invoked from the event-dispatching thread. */ private static void createAndShowGUI() { //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); //Create and set up the window. JFrame frame = new JFrame("DragColorDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and setup the content pane. JComponent newContentPane = new DragColorDemo(); newContentPane.setOpaque(true); //content panes must be opaque frame.setContentPane(newContentPane); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application"s GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); }
} /*
* ColorTransferHandler.java is used by the 1.4 DragColorDemo.java and * DragColorTextFieldDemo examples. */
/**
* An implementation of TransferHandler that adds support for dropping colors. * Dropping a color on a component having this TransferHandler changes the * foreground or the background of the component to the dropped color, according * to the value of the changesForegroundColor property. */
class ColorTransferHandler extends TransferHandler {
//The data type exported from JColorChooser. String mimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=java.awt.Color"; DataFlavor colorFlavor; private boolean changesForegroundColor = true; ColorTransferHandler() { //Try to create a DataFlavor for color. try { colorFlavor = new DataFlavor(mimeType); } catch (ClassNotFoundException e) { } } /** * Overridden to import a Color if it is available. * getChangesForegroundColor is used to determine whether the foreground or * the background color is changed. */ public boolean importData(JComponent c, Transferable t) { if (hasColorFlavor(t.getTransferDataFlavors())) { try { Color col = (Color) t.getTransferData(colorFlavor); if (getChangesForegroundColor()) { c.setForeground(col); } else { c.setBackground(col); } return true; } catch (UnsupportedFlavorException ufe) { System.out.println("importData: unsupported data flavor"); } catch (IOException ioe) { System.out.println("importData: I/O exception"); } } return false; } /** * Does the flavor list have a Color flavor? */ protected boolean hasColorFlavor(DataFlavor[] flavors) { if (colorFlavor == null) { return false; } for (int i = 0; i < flavors.length; i++) { if (colorFlavor.equals(flavors[i])) { return true; } } return false; } /** * Overridden to include a check for a color flavor. */ public boolean canImport(JComponent c, DataFlavor[] flavors) { return hasColorFlavor(flavors); } protected void setChangesForegroundColor(boolean flag) { changesForegroundColor = flag; } protected boolean getChangesForegroundColor() { return changesForegroundColor; }
}
</source>
Drag Color TextField Demo
<source lang="java">
/* From http://java.sun.ru/docs/books/tutorial/index.html */ /*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. */
/*
* DragColorTextFieldDemo.java is a 1.4 example that requires * the following files: * ColorTransferHandler.java * ColorAndTextTransferHandler.java */
import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridLayout; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.KeyEvent; import java.io.IOException; import javax.swing.BorderFactory; import javax.swing.JCheckBox; import javax.swing.JColorChooser; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.TransferHandler; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultEditorKit; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import javax.swing.text.Position; /**
* Example code that shows a text component that both accepts color (by changing * its foreground) and also exports simple text. */
public class DragColorTextFieldDemo extends JPanel {
JCheckBox toggleForeground; ColorAndTextTransferHandler colorHandler; public DragColorTextFieldDemo() { super(new BorderLayout()); JTextField textField; setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); JColorChooser chooser = new JColorChooser(); chooser.setDragEnabled(true); add(chooser, BorderLayout.PAGE_START); //Create the color transfer handler. colorHandler = new ColorAndTextTransferHandler(); //Create some text fields. JPanel buttonPanel = new JPanel(new GridLayout(3, 1)); textField = new JTextField("I can accept color/text and drag text."); textField.setTransferHandler(colorHandler); textField.setDragEnabled(true); buttonPanel.add(textField); textField = new JTextField("Me too!"); textField.setTransferHandler(colorHandler); textField.setDragEnabled(true); buttonPanel.add(textField); textField = new JTextField("Me three!"); textField.setTransferHandler(colorHandler); textField.setDragEnabled(true); buttonPanel.add(textField); add(buttonPanel, BorderLayout.CENTER); } //Create an Edit menu to support cut/copy/paste. public JMenuBar createMenuBar() { JMenuItem menuItem = null; JMenuBar menuBar = new JMenuBar(); JMenu mainMenu = new JMenu("Edit"); mainMenu.setMnemonic(KeyEvent.VK_E); menuItem = new JMenuItem(new DefaultEditorKit.CutAction()); menuItem.setText("Cut"); menuItem.setMnemonic(KeyEvent.VK_T); mainMenu.add(menuItem); menuItem = new JMenuItem(new DefaultEditorKit.CopyAction()); menuItem.setText("Copy"); menuItem.setMnemonic(KeyEvent.VK_C); mainMenu.add(menuItem); menuItem = new JMenuItem(new DefaultEditorKit.PasteAction()); menuItem.setText("Paste"); menuItem.setMnemonic(KeyEvent.VK_P); mainMenu.add(menuItem); menuBar.add(mainMenu); return menuBar; } /** * Create the GUI and show it. For thread safety, this method should be * invoked from the event-dispatching thread. */ private static void createAndShowGUI() { //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); //Create and set up the window. JFrame frame = new JFrame("DragColorTextFieldDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the menu bar and content pane. DragColorTextFieldDemo demo = new DragColorTextFieldDemo(); frame.setJMenuBar(demo.createMenuBar()); demo.setOpaque(true); //content panes must be opaque frame.setContentPane(demo); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application"s GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); }
} /*
* ColorAndTextTransferHandler.java is used by the 1.4 DragColorDemo.java * example. */
/**
* An implementation of TransferHandler that adds support for the import of * color and the import and export of text. Dropping a color on a component * having this TransferHandler changes the foreground of the component to the * imported color. */
class ColorAndTextTransferHandler extends ColorTransferHandler {
private DataFlavor stringFlavor = DataFlavor.stringFlavor; private JTextComponent source; private boolean shouldRemove; //Start and end position in the source text. //We need this information when performing a MOVE //in order to remove the dragged text from the source. Position p0 = null, p1 = null; //Get the flavors from the Transferable. //Is there a color flavor? If so, set the foreground color. //Is there a string flavor? If so, set the text property. public boolean importData(JComponent c, Transferable t) { JTextComponent tc = (JTextComponent) c; if (!canImport(c, t.getTransferDataFlavors())) { return false; } if (tc.equals(source) && (tc.getCaretPosition() >= p0.getOffset()) && (tc.getCaretPosition() <= p1.getOffset())) { shouldRemove = false; return true; } if (hasStringFlavor(t.getTransferDataFlavors())) { try { String str = (String) t.getTransferData(stringFlavor); tc.replaceSelection(str); return true; } catch (UnsupportedFlavorException ufe) { System.out.println("importData: unsupported data flavor"); } catch (IOException ioe) { System.out.println("importData: I/O exception"); } } //The ColorTransferHandler superclass handles color. return super.importData(c, t); } //Create a Transferable implementation that contains the //selected text. protected Transferable createTransferable(JComponent c) { source = (JTextComponent) c; int start = source.getSelectionStart(); int end = source.getSelectionEnd(); Document doc = source.getDocument(); if (start == end) { return null; } try { p0 = doc.createPosition(start); p1 = doc.createPosition(end); } catch (BadLocationException e) { System.out .println("Can"t create position - unable to remove text from source."); } shouldRemove = true; String data = source.getSelectedText(); return new StringSelection(data); } public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } //Remove the old text if the action is a MOVE. //However, we do not allow dropping on top of the selected text, //so in that case do nothing. protected void exportDone(JComponent c, Transferable data, int action) { if (shouldRemove && (action == MOVE)) { if ((p0 != null) && (p1 != null) && (p0.getOffset() != p1.getOffset())) { try { JTextComponent tc = (JTextComponent) c; tc.getDocument().remove(p0.getOffset(), p1.getOffset() - p0.getOffset()); } catch (BadLocationException e) { System.out.println("Can"t remove text from source."); } } } source = null; } /** * Does flavors contain a color or string Transferable? */ public boolean canImport(JComponent c, DataFlavor[] flavors) { if (hasStringFlavor(flavors)) { return true; } return super.canImport(c, flavors); } /** * Does the flavor list have a string flavor? */ protected boolean hasStringFlavor(DataFlavor[] flavors) { for (int i = 0; i < flavors.length; i++) { if (stringFlavor.equals(flavors[i])) { return true; } } return false; }
} /*
* ColorTransferHandler.java is used by the 1.4 DragColorDemo.java and * DragColorTextFieldDemo examples. */
/**
* An implementation of TransferHandler that adds support for dropping colors. * Dropping a color on a component having this TransferHandler changes the * foreground or the background of the component to the dropped color, according * to the value of the changesForegroundColor property. */
class ColorTransferHandler extends TransferHandler {
//The data type exported from JColorChooser. String mimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=java.awt.Color"; DataFlavor colorFlavor; private boolean changesForegroundColor = true; ColorTransferHandler() { //Try to create a DataFlavor for color. try { colorFlavor = new DataFlavor(mimeType); } catch (ClassNotFoundException e) { } } /** * Overridden to import a Color if it is available. * getChangesForegroundColor is used to determine whether the foreground or * the background color is changed. */ public boolean importData(JComponent c, Transferable t) { if (hasColorFlavor(t.getTransferDataFlavors())) { try { Color col = (Color) t.getTransferData(colorFlavor); if (getChangesForegroundColor()) { c.setForeground(col); } else { c.setBackground(col); } return true; } catch (UnsupportedFlavorException ufe) { System.out.println("importData: unsupported data flavor"); } catch (IOException ioe) { System.out.println("importData: I/O exception"); } } return false; } /** * Does the flavor list have a Color flavor? */ protected boolean hasColorFlavor(DataFlavor[] flavors) { if (colorFlavor == null) { return false; } for (int i = 0; i < flavors.length; i++) { if (colorFlavor.equals(flavors[i])) { return true; } } return false; } /** * Overridden to include a check for a color flavor. */ public boolean canImport(JComponent c, DataFlavor[] flavors) { return hasColorFlavor(flavors); } protected void setChangesForegroundColor(boolean flag) { changesForegroundColor = flag; } protected boolean getChangesForegroundColor() { return changesForegroundColor; }
}
</source>
Drag Drop Tree Example
<source lang="java">
/* Core SWING Advanced Programming By Kim Topley ISBN: 0 13 083292 8 Publisher: Prentice Hall
- /
import java.awt.BorderLayout; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.Autoscroll; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Arrays; import java.util.ruparator; import java.util.Iterator; import java.util.List; import java.util.Vector; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.plaf.basic.BasicTreeUI.TreeExpansionHandler; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; public class DragDropTreeExample {
public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} final JFrame f = new JFrame("FileTree Drop and Drop Example"); try { final FileTree tree = new FileTree("D:\\"); // Add a drop target to the FileTree FileTreeDropTarget target = new FileTreeDropTarget(tree); // Add a drag source to the FileTree FileTreeDragSource source = new FileTreeDragSource(tree); tree.setEditable(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); JPanel panel = new JPanel(); final JCheckBox editable = new JCheckBox("Editable"); editable.setSelected(true); panel.add(editable); editable.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { tree.setEditable(editable.isSelected()); } }); final JCheckBox enabled = new JCheckBox("Enabled"); enabled.setSelected(true); panel.add(enabled); enabled.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { tree.setEnabled(enabled.isSelected()); } }); f.getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER); f.getContentPane().add(panel, BorderLayout.SOUTH); f.setSize(500, 400); f.setVisible(true); } catch (Exception e) { System.out.println("Failed to build GUI: " + e); } }
} class FileTree extends JTree implements Autoscroll {
public static final Insets defaultScrollInsets = new Insets(8, 8, 8, 8); protected Insets scrollInsets = defaultScrollInsets; public FileTree(String path) throws FileNotFoundException, SecurityException { super((TreeModel) null); // Create the JTree itself // Use horizontal and vertical lines putClientProperty("JTree.lineStyle", "Angled"); // Create the first node FileTreeNode rootNode = new FileTreeNode(null, path); // Populate the root node with its subdirectories boolean addedNodes = rootNode.populateDirectories(true); setModel(new DefaultTreeModel(rootNode)); // Listen for Tree Selection Events addTreeExpansionListener(new TreeExpansionHandler()); } // Returns the full pathname for a path, or null if not a known path public String getPathName(TreePath path) { Object o = path.getLastPathComponent(); if (o instanceof FileTreeNode) { return ((FileTreeNode) o).fullName; } return null; } // Adds a new node to the tree after construction. // Returns the inserted node, or null if the parent // directory has not been expanded. public FileTreeNode addNode(FileTreeNode parent, String name) { int index = parent.addNode(name); if (index != -1) { ((DefaultTreeModel) getModel()).nodesWereInserted(parent, new int[] { index }); return (FileTreeNode) parent.getChildAt(index); } // No node was created return null; } // Autoscrolling support public void setScrollInsets(Insets insets) { this.scrollInsets = insets; } public Insets getScrollInsets() { return scrollInsets; } // Implementation of Autoscroll interface public Insets getAutoscrollInsets() { Rectangle r = getVisibleRect(); Dimension size = getSize(); Insets i = new Insets(r.y + scrollInsets.top, r.x + scrollInsets.left, size.height - r.y - r.height + scrollInsets.bottom, size.width - r.x - r.width + scrollInsets.right); return i; } public void autoscroll(Point location) { JScrollPane scroller = (JScrollPane) SwingUtilities.getAncestorOfClass( JScrollPane.class, this); if (scroller != null) { JScrollBar hBar = scroller.getHorizontalScrollBar(); JScrollBar vBar = scroller.getVerticalScrollBar(); Rectangle r = getVisibleRect(); if (location.x <= r.x + scrollInsets.left) { // Need to scroll left hBar.setValue(hBar.getValue() - hBar.getUnitIncrement(-1)); } if (location.y <= r.y + scrollInsets.top) { // Need to scroll up vBar.setValue(vBar.getValue() - vBar.getUnitIncrement(-1)); } if (location.x >= r.x + r.width - scrollInsets.right) { // Need to scroll right hBar.setValue(hBar.getValue() + hBar.getUnitIncrement(1)); } if (location.y >= r.y + r.height - scrollInsets.bottom) { // Need to scroll down vBar.setValue(vBar.getValue() + vBar.getUnitIncrement(1)); } } } // Inner class that represents a node in this file system tree public static class FileTreeNode extends DefaultMutableTreeNode { public FileTreeNode(String parent, String name) throws SecurityException, FileNotFoundException { this.name = name; // See if this node exists and whether it is a directory fullName = parent == null ? name : parent + File.separator + name; File f = new File(fullName); if (f.exists() == false) { throw new FileNotFoundException("File " + fullName + " does not exist"); } isDir = f.isDirectory(); // Hack for Windows which doesn"t consider a drive to be a // directory! if (isDir == false && f.isFile() == false) { isDir = true; } } // Override isLeaf to check whether this is a directory public boolean isLeaf() { return !isDir; } // Override getAllowsChildren to check whether this is a directory public boolean getAllowsChildren() { return isDir; } // Return whether this is a directory public boolean isDir() { return isDir; } // Get full path public String getFullName() { return fullName; } // For display purposes, we return our own name public String toString() { return name; } // If we are a directory, scan our contents and populate // with children. In addition, populate those children // if the "descend" flag is true. We only descend once, // to avoid recursing the whole subtree. // Returns true if some nodes were added boolean populateDirectories(boolean descend) { boolean addedNodes = false; // Do this only once if (populated == false) { File f; try { f = new File(fullName); } catch (SecurityException e) { populated = true; return false; } if (interim == true) { // We have had a quick look here before: // remove the dummy node that we added last time removeAllChildren(); interim = false; } String[] names = f.list(); // Get list of contents // Process the contents ArrayList list = new ArrayList(); for (int i = 0; i < names.length; i++) { String name = names[i]; File d = new File(fullName, name); try { FileTreeNode node = new FileTreeNode(fullName, name); list.add(node); if (descend && d.isDirectory()) { node.populateDirectories(false); } addedNodes = true; if (descend == false) { // Only add one node if not descending break; } } catch (Throwable t) { // Ignore phantoms or access problems } } if (addedNodes == true) { // Now sort the list of contained files and directories Object[] nodes = list.toArray(); Arrays.sort(nodes, new Comparator() { public boolean equals(Object o) { return false; } public int compare(Object o1, Object o2) { FileTreeNode node1 = (FileTreeNode) o1; FileTreeNode node2 = (FileTreeNode) o2; // Directories come first if (node1.isDir != node2.isDir) { return node1.isDir ? -1 : +1; } // Both directories or both files - // compare based on pathname return node1.fullName.rupareTo(node2.fullName); } }); // Add sorted items as children of this node for (int j = 0; j < nodes.length; j++) { this.add((FileTreeNode) nodes[j]); } } // If we were scanning to get all subdirectories, // or if we found no content, there is no // reason to look at this directory again, so // set populated to true. Otherwise, we set interim // so that we look again in the future if we need to if (descend == true || addedNodes == false) { populated = true; } else { // Just set interim state interim = true; } } return addedNodes; } // Adding a new file or directory after // constructing the FileTree. Returns // the index of the inserted node. public int addNode(String name) { // If not populated yet, do nothing if (populated == true) { // Do not add a new node if // the required node is already there int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { FileTreeNode node = (FileTreeNode) getChildAt(i); if (node.name.equals(name)) { // Already exists - ensure // we repopulate if (node.isDir()) { node.interim = true; node.populated = false; } return -1; } } // Add a new node try { FileTreeNode node = new FileTreeNode(fullName, name); add(node); return childCount; } catch (Exception e) { } } return -1; } protected String name; // Name of this component protected String fullName; // Full pathname protected boolean populated;// true if we have been populated protected boolean interim; // true if we are in interim state protected boolean isDir; // true if this is a directory } // Inner class that handles Tree Expansion Events protected class TreeExpansionHandler implements TreeExpansionListener { public void treeExpanded(TreeExpansionEvent evt) { TreePath path = evt.getPath(); // The expanded path JTree tree = (JTree) evt.getSource(); // The tree // Get the last component of the path and // arrange to have it fully populated. FileTreeNode node = (FileTreeNode) path.getLastPathComponent(); if (node.populateDirectories(true)) { ((DefaultTreeModel) tree.getModel()).nodeStructureChanged(node); } } public void treeCollapsed(TreeExpansionEvent evt) { // Nothing to do } }
} class FileTreeDropTarget implements DropTargetListener, PropertyChangeListener {
public FileTreeDropTarget(FileTree tree) { this.tree = tree; // Listen for changes in the enabled property tree.addPropertyChangeListener(this); // Create the DropTarget and register // it with the FileTree. dropTarget = new DropTarget(tree, DnDConstants.ACTION_COPY_OR_MOVE, this, tree.isEnabled(), null); } // Implementation of the DropTargetListener interface public void dragEnter(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("dragEnter, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Save the list of selected items saveTreeSelection(); // Get the type of object being transferred and determine // whether it is appropriate. checkTransferType(dtde); // Accept or reject the drag. boolean acceptedDrag = acceptOrRejectDrag(dtde); // Do drag-under feedback dragUnderFeedback(dtde, acceptedDrag); } public void dragExit(DropTargetEvent dte) { DnDUtils.debugPrintln("DropTarget dragExit"); // Do drag-under feedback dragUnderFeedback(null, false); // Restore the original selections restoreTreeSelection(); } public void dragOver(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dragOver, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag boolean acceptedDrag = acceptOrRejectDrag(dtde); // Do drag-under feedback dragUnderFeedback(dtde, acceptedDrag); } public void dropActionChanged(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag boolean acceptedDrag = acceptOrRejectDrag(dtde); // Do drag-under feedback dragUnderFeedback(dtde, acceptedDrag); } public void drop(DropTargetDropEvent dtde) { DnDUtils.debugPrintln("DropTarget drop, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Check the drop action if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) { // Accept the drop and get the transfer data dtde.acceptDrop(dtde.getDropAction()); Transferable transferable = dtde.getTransferable(); boolean dropSucceeded = false; try { tree.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); // Save the user"s selections saveTreeSelection(); dropSucceeded = dropFile(dtde.getDropAction(), transferable, dtde.getLocation()); DnDUtils.debugPrintln("Drop completed, success: " + dropSucceeded); } catch (Exception e) { DnDUtils.debugPrintln("Exception while handling drop " + e); } finally { tree.setCursor(Cursor.getDefaultCursor()); // Restore the user"s selections restoreTreeSelection(); dtde.dropComplete(dropSucceeded); } } else { DnDUtils.debugPrintln("Drop target rejected drop"); dtde.dropComplete(false); } } // PropertyChangeListener interface public void propertyChange(PropertyChangeEvent evt) { String propertyName = evt.getPropertyName(); if (propertyName.equals("enabled")) { // Enable the drop target if the FileTree is enabled // and vice versa. dropTarget.setActive(tree.isEnabled()); } } // Internal methods start here protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) { int dropAction = dtde.getDropAction(); int sourceActions = dtde.getSourceActions(); boolean acceptedDrag = false; DnDUtils.debugPrintln("\tSource actions are " + DnDUtils.showActions(sourceActions) + ", drop action is " + DnDUtils.showActions(dropAction)); Point location = dtde.getLocation(); boolean acceptableDropLocation = isAcceptableDropLocation(location); // Reject if the object being transferred // or the operations available are not acceptable. if (!acceptableType || (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if (!tree.isEditable()) { // Can"t drag to a read-only FileTree DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if (!acceptableDropLocation) { // Can only drag to writable directory DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { // Not offering copy or move - suggest a copy DnDUtils.debugPrintln("Drop target offering COPY"); dtde.acceptDrag(DnDConstants.ACTION_COPY); acceptedDrag = true; } else { // Offering an acceptable operation: accept DnDUtils.debugPrintln("Drop target accepting drag"); dtde.acceptDrag(dropAction); acceptedDrag = true; } return acceptedDrag; } protected void dragUnderFeedback(DropTargetDragEvent dtde, boolean acceptedDrag) { if (dtde != null && acceptedDrag) { Point location = dtde.getLocation(); if (isAcceptableDropLocation(location)) { tree.setSelectionRow(tree.getRowForLocation(location.x, location.y)); } else { tree.clearSelection(); } } else { tree.clearSelection(); } } protected void checkTransferType(DropTargetDragEvent dtde) { // Accept a list of files acceptableType = false; if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { acceptableType = true; } DnDUtils.debugPrintln("Data type acceptable - " + acceptableType); } // This method handles a drop for a list of files protected boolean dropFile(int action, Transferable transferable, Point location) throws IOException, UnsupportedFlavorException, MalformedURLException { List files = (List) transferable .getTransferData(DataFlavor.javaFileListFlavor); TreePath treePath = tree.getPathForLocation(location.x, location.y); File targetDirectory = findTargetDirectory(location); if (treePath == null || targetDirectory == null) { return false; } FileTree.FileTreeNode node = (FileTree.FileTreeNode) treePath .getLastPathComponent(); // Highlight the drop location while we perform the drop tree.setSelectionPath(treePath); // Get File objects for all files being // transferred, eliminating duplicates. File[] fileList = getFileList(files); // Don"t overwrite files by default copyOverExistingFiles = false; // Copy or move each source object to the target for (int i = 0; i < fileList.length; i++) { File f = fileList[i]; if (f.isDirectory()) { transferDirectory(action, f, targetDirectory, node); } else { try { transferFile(action, fileList[i], targetDirectory, node); } catch (IllegalStateException e) { // Cancelled by user return false; } } } return true; } protected File findTargetDirectory(Point location) { TreePath treePath = tree.getPathForLocation(location.x, location.y); if (treePath != null) { FileTree.FileTreeNode node = (FileTree.FileTreeNode) treePath .getLastPathComponent(); // Only allow a drop on a writable directory if (node.isDir()) { try { File f = new File(node.getFullName()); if (f.canWrite()) { return f; } } catch (Exception e) { } } } return null; } protected boolean isAcceptableDropLocation(Point location) { return findTargetDirectory(location) != null; } protected void saveTreeSelection() { selections = tree.getSelectionPaths(); leadSelection = tree.getLeadSelectionPath(); tree.clearSelection(); } protected void restoreTreeSelection() { tree.setSelectionPaths(selections); // Restore the lead selection if (leadSelection != null) { tree.removeSelectionPath(leadSelection); tree.addSelectionPath(leadSelection); } } // Get the list of files being transferred and // remove any duplicates. For example, if the // list contains /a/b/c and /a/b/c/d, the // second entry is removed. protected File[] getFileList(List files) { int size = files.size(); // Get the files into an array for sorting File[] f = new File[size]; Iterator iter = files.iterator(); int count = 0; while (iter.hasNext()) { f[count++] = (File) iter.next(); } // Sort the files into alphabetical order // based on pathnames. Arrays.sort(f, new Comparator() { public boolean equals(Object o1) { return false; } public int compare(Object o1, Object o2) { return ((File) o1).getAbsolutePath().rupareTo( ((File) o2).getAbsolutePath()); } }); // Remove duplicates, retaining the results in a Vector Vector v = new Vector(); char separator = System.getProperty("file.separator").charAt(0); outer: for (int i = f.length - 1; i >= 0; i--) { String secondPath = f[i].getAbsolutePath(); int secondLength = secondPath.length(); for (int j = i - 1; j >= 0; j--) { String firstPath = f[j].getAbsolutePath(); int firstLength = firstPath.length(); if (secondPath.startsWith(firstPath) && firstLength != secondLength && secondPath.charAt(firstLength) == separator) { continue outer; } } v.add(f[i]); } // Copy the retained files into an array f = new File[v.size()]; v.copyInto(f); return f; } // Copy or move a file protected void transferFile(int action, File srcFile, File targetDirectory, FileTree.FileTreeNode targetNode) { DnDUtils.debugPrintln((action == DnDConstants.ACTION_COPY ? "Copy" : "Move") + " file " + srcFile.getAbsolutePath() + " to " + targetDirectory.getAbsolutePath()); // Create a File entry for the target String name = srcFile.getName(); File newFile = new File(targetDirectory, name); if (newFile.exists()) { // Already exists - is it the same file? if (newFile.equals(srcFile)) { // Exactly the same file - ignore return; } // File of this name exists in this directory if (copyOverExistingFiles == false) { int res = JOptionPane.showOptionDialog(tree, "A file called\n " + name + "\nalready exists in the directory\n " + targetDirectory.getAbsolutePath() + "\nOverwrite it?", "File Exists", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, new String[] { "Yes", "Yes to All", "No", "Cancel" }, "No"); switch (res) { case 1: // Yes to all copyOverExistingFiles = true; case 0: // Yes break; case 2: // No return; default: // Cancel throw new IllegalStateException("Cancelled"); } } } else { // New file - create it try { newFile.createNewFile(); } catch (IOException e) { JOptionPane.showMessageDialog(tree, "Failed to create new file\n " + newFile.getAbsolutePath(), "File Creation Failed", JOptionPane.ERROR_MESSAGE); return; } } // Copy the data and close file. BufferedInputStream is = null; BufferedOutputStream os = null; try { is = new BufferedInputStream(new FileInputStream(srcFile)); os = new BufferedOutputStream(new FileOutputStream(newFile)); int size = 4096; byte[] buffer = new byte[size]; int len; while ((len = is.read(buffer, 0, size)) > 0) { os.write(buffer, 0, len); } } catch (IOException e) { JOptionPane.showMessageDialog(tree, "Failed to copy file\n " + name + "\nto directory\n " + targetDirectory.getAbsolutePath(), "File Copy Failed", JOptionPane.ERROR_MESSAGE); return; } finally { try { if (is != null) { is.close(); } if (os != null) { os.close(); } } catch (IOException e) { } } // Remove the source if this is a move operation. if (action == DnDConstants.ACTION_MOVE && System.getProperty("DnDExamples.allowRemove") != null) { srcFile.delete(); } // Update the tree display if (targetNode != null) { tree.addNode(targetNode, name); } } protected void transferDirectory(int action, File srcDir, File targetDirectory, FileTree.FileTreeNode targetNode) { DnDUtils.debugPrintln((action == DnDConstants.ACTION_COPY ? "Copy" : "Move") + " directory " + srcDir.getAbsolutePath() + " to " + targetDirectory.getAbsolutePath()); // Do not copy a directory into itself or // a subdirectory of itself. File parentDir = targetDirectory; while (parentDir != null) { if (parentDir.equals(srcDir)) { DnDUtils.debugPrintln("-- SUPPRESSED"); return; } parentDir = parentDir.getParentFile(); } // Copy the directory itself, then its contents // Create a File entry for the target String name = srcDir.getName(); File newDir = new File(targetDirectory, name); if (newDir.exists()) { // Already exists - is it the same directory? if (newDir.equals(srcDir)) { // Exactly the same file - ignore return; } } else { // Directory does not exist - create it if (newDir.mkdir() == false) { // Failed to create - abandon this directory JOptionPane.showMessageDialog(tree, "Failed to create target directory\n " + newDir.getAbsolutePath(), "Directory creation Failed", JOptionPane.ERROR_MESSAGE); return; } } // Add a node for the new directory if (targetNode != null) { targetNode = tree.addNode(targetNode, name); } // Now copy the directory content. File[] files = srcDir.listFiles(); for (int i = 0; i < files.length; i++) { File f = files[i]; if (f.isFile()) { transferFile(action, f, newDir, targetNode); } else if (f.isDirectory()) { transferDirectory(action, f, newDir, targetNode); } } // Remove the source directory after moving if (action == DnDConstants.ACTION_MOVE && System.getProperty("DnDExamples.allowRemove") != null) { srcDir.delete(); } } public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} final JFrame f = new JFrame("FileTree Drop Target Example"); try { final FileTree tree = new FileTree("D:\\"); // Add a drop target to the FileTree FileTreeDropTarget target = new FileTreeDropTarget(tree); tree.setEditable(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); JPanel panel = new JPanel(); final JCheckBox editable = new JCheckBox("Editable"); editable.setSelected(true); panel.add(editable); editable.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { tree.setEditable(editable.isSelected()); } }); final JCheckBox enabled = new JCheckBox("Enabled"); enabled.setSelected(true); panel.add(enabled); enabled.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { tree.setEnabled(enabled.isSelected()); } }); f.getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER); f.getContentPane().add(panel, BorderLayout.SOUTH); f.setSize(500, 400); f.setVisible(true); } catch (Exception e) { System.out.println("Failed to build GUI: " + e); } } protected FileTree tree; protected DropTarget dropTarget; protected boolean acceptableType; // Indicates whether data is acceptable TreePath[] selections; // Initially selected rows TreePath leadSelection; // Initial lead selection boolean copyOverExistingFiles;
}
class DnDUtils {
public static String showActions(int action) { String actions = ""; if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) { return "None"; } if ((action & DnDConstants.ACTION_COPY) != 0) { actions += "Copy "; } if ((action & DnDConstants.ACTION_MOVE) != 0) { actions += "Move "; } if ((action & DnDConstants.ACTION_LINK) != 0) { actions += "Link"; } return actions; } public static boolean isDebugEnabled() { return debugEnabled; } public static void debugPrintln(String s) { if (debugEnabled) { System.out.println(s); } } private static boolean debugEnabled = (System .getProperty("DnDExamples.debug") != null);
} class FileTreeDragSource implements DragGestureListener, DragSourceListener {
public FileTreeDragSource(FileTree tree) { this.tree = tree; // Use the default DragSource DragSource dragSource = DragSource.getDefaultDragSource(); // Create a DragGestureRecognizer and // register as the listener dragSource.createDefaultDragGestureRecognizer(tree, DnDConstants.ACTION_COPY_OR_MOVE, this); } // Implementation of DragGestureListener interface. public void dragGestureRecognized(DragGestureEvent dge) { // Get the mouse location and convert it to // a location within the tree. Point location = dge.getDragOrigin(); TreePath dragPath = tree.getPathForLocation(location.x, location.y); if (dragPath != null && tree.isPathSelected(dragPath)) { // Get the list of selected files and create a Transferable // The list of files and the is saved for use when // the drop completes. paths = tree.getSelectionPaths(); if (paths != null && paths.length > 0) { dragFiles = new File[paths.length]; for (int i = 0; i < paths.length; i++) { String pathName = tree.getPathName(paths[i]); dragFiles[i] = new File(pathName); } Transferable transferable = new FileListTransferable(dragFiles); dge.startDrag(null, transferable, this); } } } // Implementation of DragSourceListener interface public void dragEnter(DragSourceDragEvent dsde) { DnDUtils.debugPrintln("Drag Source: dragEnter, drop action = " + DnDUtils.showActions(dsde.getDropAction())); } public void dragOver(DragSourceDragEvent dsde) { DnDUtils.debugPrintln("Drag Source: dragOver, drop action = " + DnDUtils.showActions(dsde.getDropAction())); } public void dragExit(DragSourceEvent dse) { DnDUtils.debugPrintln("Drag Source: dragExit"); } public void dropActionChanged(DragSourceDragEvent dsde) { DnDUtils.debugPrintln("Drag Source: dropActionChanged, drop action = " + DnDUtils.showActions(dsde.getDropAction())); } public void dragDropEnd(DragSourceDropEvent dsde) { DnDUtils.debugPrintln("Drag Source: drop completed, drop action = " + DnDUtils.showActions(dsde.getDropAction()) + ", success: " + dsde.getDropSuccess()); // If the drop action was ACTION_MOVE, // the tree might need to be updated. if (dsde.getDropAction() == DnDConstants.ACTION_MOVE) { final File[] draggedFiles = dragFiles; final TreePath[] draggedPaths = paths; Timer tm = new Timer(200, new ActionListener() { public void actionPerformed(ActionEvent evt) { // Check whether each of the dragged files exists. // If it does not, we need to remove the node // that represents it from the tree. for (int i = 0; i < draggedFiles.length; i++) { if (draggedFiles[i].exists() == false) { // Remove this node DefaultMutableTreeNode node = (DefaultMutableTreeNode) draggedPaths[i] .getLastPathComponent(); ((DefaultTreeModel) tree.getModel()) .removeNodeFromParent(node); } } } }); tm.setRepeats(false); tm.start(); } } public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} JFrame f = new JFrame("Draggable File Tree"); try { FileTree tree = new FileTree("D:\\"); f.getContentPane().add(new JScrollPane(tree)); // Attach the drag source FileTreeDragSource dragSource = new FileTreeDragSource(tree); } catch (Exception e) { } f.pack(); f.setVisible(true); } protected FileTree tree; // The associated tree protected File[] dragFiles; // Dragged files protected TreePath[] paths; // Dragged paths
}
class FileListTransferable implements Transferable {
public FileListTransferable(File[] files) { fileList = new ArrayList(); for (int i = 0; i < files.length; i++) { fileList.add(files[i]); } } // Implementation of the Transferable interface public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[] { DataFlavor.javaFileListFlavor }; } public boolean isDataFlavorSupported(DataFlavor fl) { return fl.equals(DataFlavor.javaFileListFlavor); } public Object getTransferData(DataFlavor fl) { if (!isDataFlavorSupported(fl)) { return null; } return fileList; } List fileList; // The list of files
}
</source>
Drag File Demo
<source lang="java">
/* From http://java.sun.ru/docs/books/tutorial/index.html */ /*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. */
/*
* DragFileDemo.java is a 1.4 example that requires the following file: * FileAndTextTransferHandler.java TabbedPaneController.java */
import java.awt.BorderLayout; import java.awt.ruponent; import java.awt.Dimension; import java.awt.Insets; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.TransferHandler; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import javax.swing.text.Position; public class DragFileDemo extends JPanel implements ActionListener {
JTextArea fileArea; JFileChooser fc; JButton clear; TabbedPaneController tpc; public DragFileDemo() { super(new BorderLayout()); fc = new JFileChooser(); ; fc.setMultiSelectionEnabled(true); fc.setDragEnabled(true); fc.setControlButtonsAreShown(false); JPanel fcPanel = new JPanel(new BorderLayout()); fcPanel.add(fc, BorderLayout.CENTER); clear = new JButton("Clear All"); clear.addActionListener(this); JPanel buttonPanel = new JPanel(new BorderLayout()); buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); buttonPanel.add(clear, BorderLayout.LINE_END); JPanel upperPanel = new JPanel(new BorderLayout()); upperPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); upperPanel.add(fcPanel, BorderLayout.CENTER); upperPanel.add(buttonPanel, BorderLayout.PAGE_END); //The TabbedPaneController manages the panel that //contains the tabbed pane. When there are no files //the panel contains a plain text area. Then, as //files are dropped onto the area, the tabbed panel //replaces the file area. JTabbedPane tabbedPane = new JTabbedPane(); JPanel tabPanel = new JPanel(new BorderLayout()); tabPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); tpc = new TabbedPaneController(tabbedPane, tabPanel); JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, upperPanel, tabPanel); splitPane.setDividerLocation(400); splitPane.setPreferredSize(new Dimension(530, 650)); add(splitPane, BorderLayout.CENTER); } public void setDefaultButton() { getRootPane().setDefaultButton(clear); } public void actionPerformed(ActionEvent e) { if (e.getSource() == clear) { tpc.clearAll(); } } /** * Create the GUI and show it. For thread safety, this method should be * invoked from the event-dispatching thread. */ private static void createAndShowGUI() { //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); //Create and set up the window. JFrame frame = new JFrame("DragFileDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the menu bar and content pane. DragFileDemo demo = new DragFileDemo(); demo.setOpaque(true); //content panes must be opaque frame.setContentPane(demo); //Display the window. frame.pack(); frame.setVisible(true); demo.setDefaultButton(); } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application"s GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); }
} /*
* TabbedPaneController.java is used by the 1.4 DragFileDemo.java example. */
/*
* Class that manages area where the contents of files are displayed. When no * files are present, there is a simple JTextArea instructing users to drop a * file. As soon as a file is dropped, a JTabbedPane is placed into the window * and each file is displayed under its own tab. When all the files are removed, * the JTabbedPane is removed from the window and the simple JTextArea is again * displayed. */
class TabbedPaneController {
JPanel tabbedPanel = null; JTabbedPane tabbedPane; JPanel emptyFilePanel = null; JTextArea emptyFileArea = null; FileAndTextTransferHandler transferHandler; boolean noFiles = true; String fileSeparator; public TabbedPaneController(JTabbedPane tb, JPanel tp) { tabbedPane = tb; tabbedPanel = tp; transferHandler = new FileAndTextTransferHandler(this); fileSeparator = System.getProperty("file.separator"); //The split method in the String class uses //regular expressions to define the text used for //the split. The forward slash "\" is a special //character and must be escaped. Some look and feels, //such as Microsoft Windows, use the forward slash to //delimit the path. if ("\\".equals(fileSeparator)) { fileSeparator = "\\\\"; } init(); } public JTextArea addTab(String filename) { if (noFiles) { tabbedPanel.remove(emptyFilePanel); tabbedPanel.add(tabbedPane, BorderLayout.CENTER); noFiles = false; } String[] str = filename.split(fileSeparator); return makeTextPanel(str[str.length - 1], filename); } //Remove all tabs and their components, then put the default //file area back. public void clearAll() { if (noFiles == false) { tabbedPane.removeAll(); tabbedPanel.remove(tabbedPane); } init(); } private void init() { String defaultText = "Select one or more files from the file chooser and drop here..."; noFiles = true; if (emptyFilePanel == null) { emptyFileArea = new JTextArea(20, 15); emptyFileArea.setEditable(false); emptyFileArea.setDragEnabled(true); emptyFileArea.setTransferHandler(transferHandler); emptyFileArea.setMargin(new Insets(5, 5, 5, 5)); JScrollPane fileScrollPane = new JScrollPane(emptyFileArea); emptyFilePanel = new JPanel(new BorderLayout(), false); emptyFilePanel.add(fileScrollPane, BorderLayout.CENTER); } tabbedPanel.add(emptyFilePanel, BorderLayout.CENTER); tabbedPanel.repaint(); emptyFileArea.setText(defaultText); } protected JTextArea makeTextPanel(String name, String toolTip) { JTextArea fileArea = new JTextArea(20, 15); fileArea.setDragEnabled(true); fileArea.setTransferHandler(transferHandler); fileArea.setMargin(new Insets(5, 5, 5, 5)); JScrollPane fileScrollPane = new JScrollPane(fileArea); tabbedPane.addTab(name, null, (Component) fileScrollPane, toolTip); tabbedPane.setSelectedComponent((Component) fileScrollPane); return fileArea; }
} /*
* FileAndTextTransferHandler.java is used by the 1.4 DragFileDemo.java example. */
class FileAndTextTransferHandler extends TransferHandler {
private DataFlavor fileFlavor, stringFlavor; private TabbedPaneController tpc; private JTextArea source; private boolean shouldRemove; protected String newline = "\n"; //Start and end position in the source text. //We need this information when performing a MOVE //in order to remove the dragged text from the source. Position p0 = null, p1 = null; FileAndTextTransferHandler(TabbedPaneController t) { tpc = t; fileFlavor = DataFlavor.javaFileListFlavor; stringFlavor = DataFlavor.stringFlavor; } public boolean importData(JComponent c, Transferable t) { JTextArea tc; if (!canImport(c, t.getTransferDataFlavors())) { return false; } //A real application would load the file in another //thread in order to not block the UI. This step //was omitted here to simplify the code. try { if (hasFileFlavor(t.getTransferDataFlavors())) { String str = null; java.util.List files = (java.util.List) t .getTransferData(fileFlavor); for (int i = 0; i < files.size(); i++) { File file = (File) files.get(i); //Tell the tabbedpane controller to add //a new tab with the name of this file //on the tab. The text area that will //display the contents of the file is returned. tc = tpc.addTab(file.toString()); BufferedReader in = null; try { in = new BufferedReader(new FileReader(file)); while ((str = in.readLine()) != null) { tc.append(str + newline); } } catch (IOException ioe) { System.out .println("importData: Unable to read from file " + file.toString()); } finally { if (in != null) { try { in.close(); } catch (IOException ioe) { System.out .println("importData: Unable to close file " + file.toString()); } } } } return true; } else if (hasStringFlavor(t.getTransferDataFlavors())) { tc = (JTextArea) c; if (tc.equals(source) && (tc.getCaretPosition() >= p0.getOffset()) && (tc.getCaretPosition() <= p1.getOffset())) { shouldRemove = false; return true; } String str = (String) t.getTransferData(stringFlavor); tc.replaceSelection(str); return true; } } catch (UnsupportedFlavorException ufe) { System.out.println("importData: unsupported data flavor"); } catch (IOException ieo) { System.out.println("importData: I/O exception"); } return false; } protected Transferable createTransferable(JComponent c) { source = (JTextArea) c; int start = source.getSelectionStart(); int end = source.getSelectionEnd(); Document doc = source.getDocument(); if (start == end) { return null; } try { p0 = doc.createPosition(start); p1 = doc.createPosition(end); } catch (BadLocationException e) { System.out .println("Can"t create position - unable to remove text from source."); } shouldRemove = true; String data = source.getSelectedText(); return new StringSelection(data); } public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } //Remove the old text if the action is a MOVE. //However, we do not allow dropping on top of the selected text, //so in that case do nothing. protected void exportDone(JComponent c, Transferable data, int action) { if (shouldRemove && (action == MOVE)) { if ((p0 != null) && (p1 != null) && (p0.getOffset() != p1.getOffset())) { try { JTextComponent tc = (JTextComponent) c; tc.getDocument().remove(p0.getOffset(), p1.getOffset() - p0.getOffset()); } catch (BadLocationException e) { System.out.println("Can"t remove text from source."); } } } source = null; } public boolean canImport(JComponent c, DataFlavor[] flavors) { if (hasFileFlavor(flavors)) { return true; } if (hasStringFlavor(flavors)) { return true; } return false; } private boolean hasFileFlavor(DataFlavor[] flavors) { for (int i = 0; i < flavors.length; i++) { if (fileFlavor.equals(flavors[i])) { return true; } } return false; } private boolean hasStringFlavor(DataFlavor[] flavors) { for (int i = 0; i < flavors.length; i++) { if (stringFlavor.equals(flavors[i])) { return true; } } return false; }
}
</source>
Drag List Demo
<source lang="java">
/* From http://java.sun.ru/docs/books/tutorial/index.html */ /*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. */
/*
* DragListDemo.java is a 1.4 example that requires the following file: * ArrayListTransferHandler.java */
import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import java.util.ArrayList; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; import javax.swing.TransferHandler; public class DragListDemo extends JPanel {
ArrayListTransferHandler arrayListHandler; public DragListDemo() { arrayListHandler = new ArrayListTransferHandler(); JList list1, list2; DefaultListModel list1Model = new DefaultListModel(); list1Model.addElement("0 (list 1)"); list1Model.addElement("1 (list 1)"); list1Model.addElement("2 (list 1)"); list1Model.addElement("3 (list 1)"); list1Model.addElement("4 (list 1)"); list1Model.addElement("5 (list 1)"); list1Model.addElement("6 (list 1)"); list1 = new JList(list1Model); list1.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); list1.setTransferHandler(arrayListHandler); list1.setDragEnabled(true); JScrollPane list1View = new JScrollPane(list1); list1View.setPreferredSize(new Dimension(200, 100)); JPanel panel1 = new JPanel(); panel1.setLayout(new BorderLayout()); panel1.add(list1View, BorderLayout.CENTER); panel1.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); DefaultListModel list2Model = new DefaultListModel(); list2Model.addElement("0 (list 2)"); list2Model.addElement("1 (list 2)"); list2Model.addElement("2 (list 2)"); list2Model.addElement("3 (list 2)"); list2Model.addElement("4 (list 2)"); list2Model.addElement("5 (list 2)"); list2Model.addElement("6 (list 2)"); list2 = new JList(list2Model); list2.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); list2.setTransferHandler(arrayListHandler); list2.setDragEnabled(true); JScrollPane list2View = new JScrollPane(list2); list2View.setPreferredSize(new Dimension(200, 100)); JPanel panel2 = new JPanel(); panel2.setLayout(new BorderLayout()); panel2.add(list2View, BorderLayout.CENTER); panel2.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); setLayout(new BorderLayout()); add(panel1, BorderLayout.LINE_START); add(panel2, BorderLayout.LINE_END); setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); } /** * Create the GUI and show it. For thread safety, this method should be * invoked from the event-dispatching thread. */ private static void createAndShowGUI() { //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); //Create and set up the window. JFrame frame = new JFrame("DragListDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the content pane. DragListDemo demo = new DragListDemo(); frame.setContentPane(demo); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application"s GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); }
} /*
* ArrayListTransferHandler.java is used by the 1.4 DragListDemo.java example. */
class ArrayListTransferHandler extends TransferHandler {
DataFlavor localArrayListFlavor, serialArrayListFlavor; String localArrayListType = DataFlavor.javaJVMLocalObjectMimeType + ";class=java.util.ArrayList"; JList source = null; int[] indices = null; int addIndex = -1; //Location where items were added int addCount = 0; //Number of items added public ArrayListTransferHandler() { try { localArrayListFlavor = new DataFlavor(localArrayListType); } catch (ClassNotFoundException e) { System.out .println("ArrayListTransferHandler: unable to create data flavor"); } serialArrayListFlavor = new DataFlavor(ArrayList.class, "ArrayList"); } public boolean importData(JComponent c, Transferable t) { JList target = null; ArrayList alist = null; if (!canImport(c, t.getTransferDataFlavors())) { return false; } try { target = (JList) c; if (hasLocalArrayListFlavor(t.getTransferDataFlavors())) { alist = (ArrayList) t.getTransferData(localArrayListFlavor); } else if (hasSerialArrayListFlavor(t.getTransferDataFlavors())) { alist = (ArrayList) t.getTransferData(serialArrayListFlavor); } else { return false; } } catch (UnsupportedFlavorException ufe) { System.out.println("importData: unsupported data flavor"); return false; } catch (IOException ioe) { System.out.println("importData: I/O exception"); return false; } //At this point we use the same code to retrieve the data //locally or serially. //We"ll drop at the current selected index. int index = target.getSelectedIndex(); //Prevent the user from dropping data back on itself. //For example, if the user is moving items #4,#5,#6 and #7 and //attempts to insert the items after item #5, this would //be problematic when removing the original items. //This is interpreted as dropping the same data on itself //and has no effect. if (source.equals(target)) { if (indices != null && index >= indices[0] - 1 && index <= indices[indices.length - 1]) { indices = null; return true; } } DefaultListModel listModel = (DefaultListModel) target.getModel(); int max = listModel.getSize(); if (index < 0) { index = max; } else { index++; if (index > max) { index = max; } } addIndex = index; addCount = alist.size(); for (int i = 0; i < alist.size(); i++) { listModel.add(index++, alist.get(i)); } return true; } protected void exportDone(JComponent c, Transferable data, int action) { if ((action == MOVE) && (indices != null)) { DefaultListModel model = (DefaultListModel) source.getModel(); //If we are moving items around in the same list, we //need to adjust the indices accordingly since those //after the insertion point have moved. if (addCount > 0) { for (int i = 0; i < indices.length; i++) { if (indices[i] > addIndex) { indices[i] += addCount; } } } for (int i = indices.length - 1; i >= 0; i--) model.remove(indices[i]); } indices = null; addIndex = -1; addCount = 0; } private boolean hasLocalArrayListFlavor(DataFlavor[] flavors) { if (localArrayListFlavor == null) { return false; } for (int i = 0; i < flavors.length; i++) { if (flavors[i].equals(localArrayListFlavor)) { return true; } } return false; } private boolean hasSerialArrayListFlavor(DataFlavor[] flavors) { if (serialArrayListFlavor == null) { return false; } for (int i = 0; i < flavors.length; i++) { if (flavors[i].equals(serialArrayListFlavor)) { return true; } } return false; } public boolean canImport(JComponent c, DataFlavor[] flavors) { if (hasLocalArrayListFlavor(flavors)) { return true; } if (hasSerialArrayListFlavor(flavors)) { return true; } return false; } protected Transferable createTransferable(JComponent c) { if (c instanceof JList) { source = (JList) c; indices = source.getSelectedIndices(); Object[] values = source.getSelectedValues(); if (values == null || values.length == 0) { return null; } ArrayList alist = new ArrayList(values.length); for (int i = 0; i < values.length; i++) { Object o = values[i]; String str = o.toString(); if (str == null) str = ""; alist.add(str); } return new ArrayListTransferable(alist); } return null; } public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } public class ArrayListTransferable implements Transferable { ArrayList data; public ArrayListTransferable(ArrayList alist) { data = alist; } public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { if (!isDataFlavorSupported(flavor)) { throw new UnsupportedFlavorException(flavor); } return data; } public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[] { localArrayListFlavor, serialArrayListFlavor }; } public boolean isDataFlavorSupported(DataFlavor flavor) { if (localArrayListFlavor.equals(flavor)) { return true; } if (serialArrayListFlavor.equals(flavor)) { return true; } return false; } }
}
</source>
Drag Picture Demo
<source lang="java">
/* From http://java.sun.ru/docs/books/tutorial/index.html */ /*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. */
/*
* DragPictureDemo.java is a 1.4 example that requires the following files: * Picture.java DTPicture.java PictureTransferHandler.java images/Maya.jpg * images/Anya.jpg images/Laine.jpg images/Cosmo.jpg images/Adele.jpg * images/Alexi.jpg */
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.Image; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.io.IOException; import javax.accessibility.Accessible; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.TransferHandler; public class DragPictureDemo extends JPanel {
DTPicture pic1, pic2, pic3, pic4, pic5, pic6, pic7, pic8, pic9, pic10, pic11, pic12; static String mayaString = "Maya"; static String anyaString = "Anya"; static String laineString = "Laine"; static String cosmoString = "Cosmo"; static String adeleString = "Adele"; static String alexiString = "Alexi"; PictureTransferHandler picHandler; public DragPictureDemo() { super(new BorderLayout()); picHandler = new PictureTransferHandler(); JPanel mugshots = new JPanel(new GridLayout(4, 3)); pic1 = new DTPicture(createImageIcon("images/" + mayaString + ".jpg", mayaString).getImage()); pic1.setTransferHandler(picHandler); mugshots.add(pic1); pic2 = new DTPicture(createImageIcon("images/" + anyaString + ".jpg", anyaString).getImage()); pic2.setTransferHandler(picHandler); mugshots.add(pic2); pic3 = new DTPicture(createImageIcon("images/" + laineString + ".jpg", laineString).getImage()); pic3.setTransferHandler(picHandler); mugshots.add(pic3); pic4 = new DTPicture(createImageIcon("images/" + cosmoString + ".jpg", cosmoString).getImage()); pic4.setTransferHandler(picHandler); mugshots.add(pic4); pic5 = new DTPicture(createImageIcon("images/" + adeleString + ".jpg", adeleString).getImage()); pic5.setTransferHandler(picHandler); mugshots.add(pic5); pic6 = new DTPicture(createImageIcon("images/" + alexiString + ".jpg", alexiString).getImage()); pic6.setTransferHandler(picHandler); mugshots.add(pic6); //These six components with no pictures provide handy //drop targets. pic7 = new DTPicture(null); pic7.setTransferHandler(picHandler); mugshots.add(pic7); pic8 = new DTPicture(null); pic8.setTransferHandler(picHandler); mugshots.add(pic8); pic9 = new DTPicture(null); pic9.setTransferHandler(picHandler); mugshots.add(pic9); pic10 = new DTPicture(null); pic10.setTransferHandler(picHandler); mugshots.add(pic10); pic11 = new DTPicture(null); pic11.setTransferHandler(picHandler); mugshots.add(pic11); pic12 = new DTPicture(null); pic12.setTransferHandler(picHandler); mugshots.add(pic12); setPreferredSize(new Dimension(450, 630)); add(mugshots, BorderLayout.CENTER); setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); } /** Returns an ImageIcon, or null if the path was invalid. */ protected static ImageIcon createImageIcon(String path, String description) { java.net.URL imageURL = DragPictureDemo.class.getResource(path); if (imageURL == null) { System.err.println("Resource not found: " + path); return null; } else { return new ImageIcon(imageURL, description); } } /** * Create the GUI and show it. For thread safety, this method should be * invoked from the event-dispatching thread. */ private static void createAndShowGUI() { //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); //Create and set up the window. JFrame frame = new JFrame("DragPictureDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the menu bar and content pane. DragPictureDemo demo = new DragPictureDemo(); demo.setOpaque(true); //content panes must be opaque frame.setContentPane(demo); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application"s GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); }
} /*
* PictureTransferHandler.java is used by the 1.4 DragPictureDemo.java example. */
class PictureTransferHandler extends TransferHandler {
DataFlavor pictureFlavor = DataFlavor.imageFlavor; DTPicture sourcePic; boolean shouldRemove; public boolean importData(JComponent c, Transferable t) { Image image; if (canImport(c, t.getTransferDataFlavors())) { DTPicture pic = (DTPicture) c; //Don"t drop on myself. if (sourcePic == pic) { shouldRemove = false; return true; } try { image = (Image) t.getTransferData(pictureFlavor); //Set the component to the new picture. pic.setImage(image); return true; } catch (UnsupportedFlavorException ufe) { System.out.println("importData: unsupported data flavor"); } catch (IOException ioe) { System.out.println("importData: I/O exception"); } } return false; } protected Transferable createTransferable(JComponent c) { sourcePic = (DTPicture) c; shouldRemove = true; return new PictureTransferable(sourcePic); } public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } protected void exportDone(JComponent c, Transferable data, int action) { if (shouldRemove && (action == MOVE)) { sourcePic.setImage(null); } sourcePic = null; } public boolean canImport(JComponent c, DataFlavor[] flavors) { for (int i = 0; i < flavors.length; i++) { if (pictureFlavor.equals(flavors[i])) { return true; } } return false; } class PictureTransferable implements Transferable { private Image image; PictureTransferable(DTPicture pic) { image = pic.image; } public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { if (!isDataFlavorSupported(flavor)) { throw new UnsupportedFlavorException(flavor); } return image; } public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[] { pictureFlavor }; } public boolean isDataFlavorSupported(DataFlavor flavor) { return pictureFlavor.equals(flavor); } }
} /*
* DTPicture.java is used by the 1.4 DragPictureDemo.java example. */
//A subclass of Picture that supports Data Transfer. class DTPicture extends Picture implements MouseMotionListener {
private MouseEvent firstMouseEvent = null; private static boolean installInputMapBindings = true; public DTPicture(Image image) { super(image); addMouseMotionListener(this); //Add the cut/copy/paste key bindings to the input map. //Note that this step is redundant if you are installing //menu accelerators that cause these actions to be invoked. //DragPictureDemo does not use menu accelerators and, since //the default value of installInputMapBindings is true, //the bindings are installed. DragPictureDemo2 does use //menu accelerators and so calls setInstallInputMapBindings //with a value of false. Your program would do one or the //other, but not both. if (installInputMapBindings) { InputMap imap = this.getInputMap(); imap.put(KeyStroke.getKeyStroke("ctrl X"), TransferHandler .getCutAction().getValue(Action.NAME)); imap.put(KeyStroke.getKeyStroke("ctrl C"), TransferHandler .getCopyAction().getValue(Action.NAME)); imap.put(KeyStroke.getKeyStroke("ctrl V"), TransferHandler .getPasteAction().getValue(Action.NAME)); } //Add the cut/copy/paste actions to the action map. //This step is necessary because the menu"s action listener //looks for these actions to fire. ActionMap map = this.getActionMap(); map.put(TransferHandler.getCutAction().getValue(Action.NAME), TransferHandler.getCutAction()); map.put(TransferHandler.getCopyAction().getValue(Action.NAME), TransferHandler.getCopyAction()); map.put(TransferHandler.getPasteAction().getValue(Action.NAME), TransferHandler.getPasteAction()); } public void setImage(Image image) { this.image = image; this.repaint(); } public void mousePressed(MouseEvent e) { //Don"t bother to drag if there is no image. if (image == null) return; firstMouseEvent = e; e.consume(); } public void mouseDragged(MouseEvent e) { //Don"t bother to drag if the component displays no image. if (image == null) return; if (firstMouseEvent != null) { e.consume(); //If they are holding down the control key, COPY rather than MOVE int ctrlMask = InputEvent.CTRL_DOWN_MASK; int action = ((e.getModifiersEx() & ctrlMask) == ctrlMask) ? TransferHandler.COPY : TransferHandler.MOVE; int dx = Math.abs(e.getX() - firstMouseEvent.getX()); int dy = Math.abs(e.getY() - firstMouseEvent.getY()); //Arbitrarily define a 5-pixel shift as the //official beginning of a drag. if (dx > 5 || dy > 5) { //This is a drag, not a click. JComponent c = (JComponent) e.getSource(); TransferHandler handler = c.getTransferHandler(); //Tell the transfer handler to initiate the drag. handler.exportAsDrag(c, firstMouseEvent, action); firstMouseEvent = null; } } } public void mouseReleased(MouseEvent e) { firstMouseEvent = null; } public void mouseMoved(MouseEvent e) { } //This method is necessary because DragPictureDemo and //DragPictureDemo2 both use this class and DragPictureDemo //needs to have the input map bindings installed for //cut/copy/paste. DragPictureDemo2 uses menu accelerators //and does not need to have the input map bindings installed. //Your program would use one approach or the other, but not //both. The default for installInputMapBindings is true. public static void setInstallInputMapBindings(boolean flag) { installInputMapBindings = flag; } public static boolean getInstallInputMapBindingds() { //for completeness return installInputMapBindings; }
} /*
* Picture.java is used by the 1.4 TrackFocusDemo.java and DragPictureDemo.java * examples. */
class Picture extends JComponent implements MouseListener, FocusListener,
Accessible { Image image; public Picture(Image image) { this.image = image; setFocusable(true); addMouseListener(this); addFocusListener(this); } public void mouseClicked(MouseEvent e) { //Since the user clicked on us, let"s get focus! requestFocusInWindow(); } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } public void focusGained(FocusEvent e) { //Draw the component with a red border //indicating that it has focus. this.repaint(); } public void focusLost(FocusEvent e) { //Draw the component with a black border //indicating that it doesn"t have focus. this.repaint(); } protected void paintComponent(Graphics graphics) { Graphics g = graphics.create(); //Draw in our entire space, even if isOpaque is false. g.setColor(Color.WHITE); g.fillRect(0, 0, image == null ? 125 : image.getWidth(this), image == null ? 125 : image.getHeight(this)); if (image != null) { //Draw image at its natural size of 125x125. g.drawImage(image, 0, 0, this); } //Add a border, red if picture currently has focus if (isFocusOwner()) { g.setColor(Color.RED); } else { g.setColor(Color.BLACK); } g.drawRect(0, 0, image == null ? 125 : image.getWidth(this), image == null ? 125 : image.getHeight(this)); g.dispose(); }
}
</source>
Drag Picture Demo 2
<source lang="java">
/* From http://java.sun.ru/docs/books/tutorial/index.html */ /*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. */
/*
* DragPictureDemo2.java is a 1.4 example that requires the following files: * Picture.java DTPicture.java PictureTransferHandler.java * TransferActionListener.java images/Maya.jpg images/Anya.jpg images/Laine.jpg * images/Cosmo.jpg images/Adele.jpg images/Alexi.jpg */
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.Image; import java.awt.KeyboardFocusManager; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import javax.accessibility.Accessible; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.TransferHandler; //A version of DragPictureDemo that creates an //Edit menu with cut/copy/paste actions. //This demo adds a class called TransferActionDemo //that transfers the cut/copy/paste menu action //to the currently focused component. public class DragPictureDemo2 extends JPanel {
DTPicture pic1, pic2, pic3, pic4, pic5, pic6, pic7, pic8, pic9, pic10, pic11, pic12; static String mayaString = "Maya"; static String anyaString = "Anya"; static String laineString = "Laine"; static String cosmoString = "Cosmo"; static String adeleString = "Adele"; static String alexiString = "Alexi"; PictureTransferHandler picHandler; public DragPictureDemo2() { super(new BorderLayout()); picHandler = new PictureTransferHandler(); //Since we are using keyboard accelerators, we don"t //need the component to install its own input map //bindings. DTPicture.setInstallInputMapBindings(false); JPanel mugshots = new JPanel(new GridLayout(4, 3)); pic1 = new DTPicture(createImageIcon("images/" + mayaString + ".jpg", mayaString).getImage()); pic1.setTransferHandler(picHandler); mugshots.add(pic1); pic2 = new DTPicture(createImageIcon("images/" + anyaString + ".jpg", anyaString).getImage()); pic2.setTransferHandler(picHandler); mugshots.add(pic2); pic3 = new DTPicture(createImageIcon("images/" + laineString + ".jpg", laineString).getImage()); pic3.setTransferHandler(picHandler); mugshots.add(pic3); pic4 = new DTPicture(createImageIcon("images/" + cosmoString + ".jpg", cosmoString).getImage()); pic4.setTransferHandler(picHandler); mugshots.add(pic4); pic5 = new DTPicture(createImageIcon("images/" + adeleString + ".jpg", adeleString).getImage()); pic5.setTransferHandler(picHandler); mugshots.add(pic5); pic6 = new DTPicture(createImageIcon("images/" + alexiString + ".jpg", alexiString).getImage()); pic6.setTransferHandler(picHandler); mugshots.add(pic6); //These six components with no pictures provide handy //drop targets. pic7 = new DTPicture(null); pic7.setTransferHandler(picHandler); mugshots.add(pic7); pic8 = new DTPicture(null); pic8.setTransferHandler(picHandler); mugshots.add(pic8); pic9 = new DTPicture(null); pic9.setTransferHandler(picHandler); mugshots.add(pic9); pic10 = new DTPicture(null); pic10.setTransferHandler(picHandler); mugshots.add(pic10); pic11 = new DTPicture(null); pic11.setTransferHandler(picHandler); mugshots.add(pic11); pic12 = new DTPicture(null); pic12.setTransferHandler(picHandler); mugshots.add(pic12); setPreferredSize(new Dimension(450, 630)); add(mugshots, BorderLayout.CENTER); setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); } //Create an Edit menu to support cut/copy/paste. public JMenuBar createMenuBar() { JMenuItem menuItem = null; JMenuBar menuBar = new JMenuBar(); JMenu mainMenu = new JMenu("Edit"); mainMenu.setMnemonic(KeyEvent.VK_E); TransferActionListener actionListener = new TransferActionListener(); menuItem = new JMenuItem("Cut"); menuItem.setActionCommand((String) TransferHandler.getCutAction() .getValue(Action.NAME)); menuItem.addActionListener(actionListener); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK)); menuItem.setMnemonic(KeyEvent.VK_T); mainMenu.add(menuItem); menuItem = new JMenuItem("Copy"); menuItem.setActionCommand((String) TransferHandler.getCopyAction() .getValue(Action.NAME)); menuItem.addActionListener(actionListener); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK)); menuItem.setMnemonic(KeyEvent.VK_C); mainMenu.add(menuItem); menuItem = new JMenuItem("Paste"); menuItem.setActionCommand((String) TransferHandler.getPasteAction() .getValue(Action.NAME)); menuItem.addActionListener(actionListener); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.CTRL_MASK)); menuItem.setMnemonic(KeyEvent.VK_P); mainMenu.add(menuItem); menuBar.add(mainMenu); return menuBar; } /** Returns an ImageIcon, or null if the path was invalid. */ protected static ImageIcon createImageIcon(String path, String description) { java.net.URL imageURL = DragPictureDemo2.class.getResource(path); if (imageURL == null) { System.err.println("Resource not found: " + path); return null; } else { return new ImageIcon(imageURL, description); } } /** * Create the GUI and show it. For thread safety, this method should be * invoked from the event-dispatching thread. */ private static void createAndShowGUI() { //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); //Create and set up the window. JFrame frame = new JFrame("DragPictureDemo2"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the menu bar and content pane. DragPictureDemo2 demo = new DragPictureDemo2(); frame.setJMenuBar(demo.createMenuBar()); demo.setOpaque(true); //content panes must be opaque frame.setContentPane(demo); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application"s GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); }
} /*
* DTPicture.java is used by the 1.4 DragPictureDemo.java example. */
//A subclass of Picture that supports Data Transfer. class DTPicture extends Picture implements MouseMotionListener {
private MouseEvent firstMouseEvent = null; private static boolean installInputMapBindings = true; public DTPicture(Image image) { super(image); addMouseMotionListener(this); //Add the cut/copy/paste key bindings to the input map. //Note that this step is redundant if you are installing //menu accelerators that cause these actions to be invoked. //DragPictureDemo does not use menu accelerators and, since //the default value of installInputMapBindings is true, //the bindings are installed. DragPictureDemo2 does use //menu accelerators and so calls setInstallInputMapBindings //with a value of false. Your program would do one or the //other, but not both. if (installInputMapBindings) { InputMap imap = this.getInputMap(); imap.put(KeyStroke.getKeyStroke("ctrl X"), TransferHandler .getCutAction().getValue(Action.NAME)); imap.put(KeyStroke.getKeyStroke("ctrl C"), TransferHandler .getCopyAction().getValue(Action.NAME)); imap.put(KeyStroke.getKeyStroke("ctrl V"), TransferHandler .getPasteAction().getValue(Action.NAME)); } //Add the cut/copy/paste actions to the action map. //This step is necessary because the menu"s action listener //looks for these actions to fire. ActionMap map = this.getActionMap(); map.put(TransferHandler.getCutAction().getValue(Action.NAME), TransferHandler.getCutAction()); map.put(TransferHandler.getCopyAction().getValue(Action.NAME), TransferHandler.getCopyAction()); map.put(TransferHandler.getPasteAction().getValue(Action.NAME), TransferHandler.getPasteAction()); } public void setImage(Image image) { this.image = image; this.repaint(); } public void mousePressed(MouseEvent e) { //Don"t bother to drag if there is no image. if (image == null) return; firstMouseEvent = e; e.consume(); } public void mouseDragged(MouseEvent e) { //Don"t bother to drag if the component displays no image. if (image == null) return; if (firstMouseEvent != null) { e.consume(); //If they are holding down the control key, COPY rather than MOVE int ctrlMask = InputEvent.CTRL_DOWN_MASK; int action = ((e.getModifiersEx() & ctrlMask) == ctrlMask) ? TransferHandler.COPY : TransferHandler.MOVE; int dx = Math.abs(e.getX() - firstMouseEvent.getX()); int dy = Math.abs(e.getY() - firstMouseEvent.getY()); //Arbitrarily define a 5-pixel shift as the //official beginning of a drag. if (dx > 5 || dy > 5) { //This is a drag, not a click. JComponent c = (JComponent) e.getSource(); TransferHandler handler = c.getTransferHandler(); //Tell the transfer handler to initiate the drag. handler.exportAsDrag(c, firstMouseEvent, action); firstMouseEvent = null; } } } public void mouseReleased(MouseEvent e) { firstMouseEvent = null; } public void mouseMoved(MouseEvent e) { } //This method is necessary because DragPictureDemo and //DragPictureDemo2 both use this class and DragPictureDemo //needs to have the input map bindings installed for //cut/copy/paste. DragPictureDemo2 uses menu accelerators //and does not need to have the input map bindings installed. //Your program would use one approach or the other, but not //both. The default for installInputMapBindings is true. public static void setInstallInputMapBindings(boolean flag) { installInputMapBindings = flag; } public static boolean getInstallInputMapBindingds() { //for completeness return installInputMapBindings; }
} /*
* Picture.java is used by the 1.4 TrackFocusDemo.java and DragPictureDemo.java * examples. */
class Picture extends JComponent implements MouseListener, FocusListener,
Accessible { Image image; public Picture(Image image) { this.image = image; setFocusable(true); addMouseListener(this); addFocusListener(this); } public void mouseClicked(MouseEvent e) { //Since the user clicked on us, let"s get focus! requestFocusInWindow(); } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } public void focusGained(FocusEvent e) { //Draw the component with a red border //indicating that it has focus. this.repaint(); } public void focusLost(FocusEvent e) { //Draw the component with a black border //indicating that it doesn"t have focus. this.repaint(); } protected void paintComponent(Graphics graphics) { Graphics g = graphics.create(); //Draw in our entire space, even if isOpaque is false. g.setColor(Color.WHITE); g.fillRect(0, 0, image == null ? 125 : image.getWidth(this), image == null ? 125 : image.getHeight(this)); if (image != null) { //Draw image at its natural size of 125x125. g.drawImage(image, 0, 0, this); } //Add a border, red if picture currently has focus if (isFocusOwner()) { g.setColor(Color.RED); } else { g.setColor(Color.BLACK); } g.drawRect(0, 0, image == null ? 125 : image.getWidth(this), image == null ? 125 : image.getHeight(this)); g.dispose(); }
} /*
* PictureTransferHandler.java is used by the 1.4 DragPictureDemo.java example. */
class PictureTransferHandler extends TransferHandler {
DataFlavor pictureFlavor = DataFlavor.imageFlavor; DTPicture sourcePic; boolean shouldRemove; public boolean importData(JComponent c, Transferable t) { Image image; if (canImport(c, t.getTransferDataFlavors())) { DTPicture pic = (DTPicture) c; //Don"t drop on myself. if (sourcePic == pic) { shouldRemove = false; return true; } try { image = (Image) t.getTransferData(pictureFlavor); //Set the component to the new picture. pic.setImage(image); return true; } catch (UnsupportedFlavorException ufe) { System.out.println("importData: unsupported data flavor"); } catch (IOException ioe) { System.out.println("importData: I/O exception"); } } return false; } protected Transferable createTransferable(JComponent c) { sourcePic = (DTPicture) c; shouldRemove = true; return new PictureTransferable(sourcePic); } public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } protected void exportDone(JComponent c, Transferable data, int action) { if (shouldRemove && (action == MOVE)) { sourcePic.setImage(null); } sourcePic = null; } public boolean canImport(JComponent c, DataFlavor[] flavors) { for (int i = 0; i < flavors.length; i++) { if (pictureFlavor.equals(flavors[i])) { return true; } } return false; } class PictureTransferable implements Transferable { private Image image; PictureTransferable(DTPicture pic) { image = pic.image; } public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { if (!isDataFlavorSupported(flavor)) { throw new UnsupportedFlavorException(flavor); } return image; } public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[] { pictureFlavor }; } public boolean isDataFlavorSupported(DataFlavor flavor) { return pictureFlavor.equals(flavor); } }
} /*
* TransferActionListener.java is used by the 1.4 DragPictureDemo.java example. */
/*
* A class that tracks the focused component. This is necessary to delegate the * menu cut/copy/paste commands to the right component. An instance of this * class is listening and when the user fires one of these commands, it calls * the appropriate action on the currently focused component. */
class TransferActionListener implements ActionListener, PropertyChangeListener {
private JComponent focusOwner = null; public TransferActionListener() { KeyboardFocusManager manager = KeyboardFocusManager .getCurrentKeyboardFocusManager(); manager.addPropertyChangeListener("permanentFocusOwner", this); } public void propertyChange(PropertyChangeEvent e) { Object o = e.getNewValue(); if (o instanceof JComponent) { focusOwner = (JComponent) o; } else { focusOwner = null; } } public void actionPerformed(ActionEvent e) { if (focusOwner == null) return; String action = (String) e.getActionCommand(); Action a = focusOwner.getActionMap().get(action); if (a != null) { a.actionPerformed(new ActionEvent(focusOwner, ActionEvent.ACTION_PERFORMED, null)); } }
}
</source>
Dropper - show File Drop Target from Drag-n-Drop
<source lang="java">
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002. * All rights reserved. Software written by Ian F. Darwin and others. * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS"" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s, * pioneering role in inventing and promulgating (and standardizing) the Java * language and environment is gratefully acknowledged. * * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for * inventing predecessor languages C and C++ is also gratefully acknowledged. */
import java.awt.Toolkit; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; import java.util.List; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.TransferHandler; /**
* Dropper - show File Drop Target from Drag-n-Drop * * @version $Id: Dropper.java,v 1.1 2004/04/10 00:12:25 ian Exp $ */
public class Dropper extends JFrame {
/** * Construct trivial GUI and connect a TransferHandler to it. */ public Dropper() { super("Drop Target"); JComponent cp = (JComponent) getContentPane(); cp.setTransferHandler(new MyFileTransferHandler()); // see below setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(150, 150); } /** Instantiate and show the GUI */ public static void main(String[] args) { new Dropper().setVisible(true); }
} /** Non-public class to handle filename drops */ class MyFileTransferHandler extends TransferHandler {
/** * @see javax.swing.TransferHandler#canImport(javax.swing.JComponent, * java.awt.datatransfer.DataFlavor[]) */ public boolean canImport(JComponent arg0, DataFlavor[] arg1) { for (int i = 0; i < arg1.length; i++) { DataFlavor flavor = arg1[i]; if (flavor.equals(DataFlavor.javaFileListFlavor)) { System.out.println("canImport: JavaFileList FLAVOR: " + flavor); return true; } if (flavor.equals(DataFlavor.stringFlavor)) { System.out.println("canImport: String FLAVOR: " + flavor); return true; } System.err.println("canImport: Rejected Flavor: " + flavor); } // Didn"t find any that match, so: return false; } /** * Do the actual import. * * @see javax.swing.TransferHandler#importData(javax.swing.JComponent, * java.awt.datatransfer.Transferable) */ public boolean importData(JComponent comp, Transferable t) { DataFlavor[] flavors = t.getTransferDataFlavors(); System.out.println("Trying to import:" + t); System.out.println("... which has " + flavors.length + " flavors."); for (int i = 0; i < flavors.length; i++) { DataFlavor flavor = flavors[i]; try { if (flavor.equals(DataFlavor.javaFileListFlavor)) { System.out.println("importData: FileListFlavor"); List l = (List) t .getTransferData(DataFlavor.javaFileListFlavor); Iterator iter = l.iterator(); while (iter.hasNext()) { File file = (File) iter.next(); System.out.println("GOT FILE: " + file.getCanonicalPath()); // Now do something with the file... } return true; } else if (flavor.equals(DataFlavor.stringFlavor)) { System.out.println("importData: String Flavor"); String fileOrURL = (String) t.getTransferData(flavor); System.out.println("GOT STRING: " + fileOrURL); try { URL url = new URL(fileOrURL); System.out.println("Valid URL: " + url.toString()); // Do something with the contents... return true; } catch (MalformedURLException ex) { System.err.println("Not a valid URL"); return false; } // now do something with the String. } else { System.out.println("importData rejected: " + flavor); // Don"t return; try next flavor. } } catch (IOException ex) { System.err.println("IOError getting data: " + ex); } catch (UnsupportedFlavorException e) { System.err.println("Unsupported Flavor: " + e); } } // If you get here, I didn"t like the flavor. Toolkit.getDefaultToolkit().beep(); return false; }
}
</source>
Editor Drop Target
<source lang="java">
/* Core SWING Advanced Programming By Kim Topley ISBN: 0 13 083292 8 Publisher: Prentice Hall
- /
import java.awt.BorderLayout; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.UIManager; public class EditorDropTarget implements DropTargetListener {
public EditorDropTarget(JEditorPane pane) { this.pane = pane; // Create the DropTarget and register // it with the JEditorPane. dropTarget = new DropTarget(pane, DnDConstants.ACTION_COPY_OR_MOVE, this, true, null); } // Implementation of the DropTargetListener interface public void dragEnter(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("dragEnter, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Get the type of object being transferred and determine // whether it is appropriate. checkTransferType(dtde); // Accept or reject the drag. acceptOrRejectDrag(dtde); } public void dragExit(DropTargetEvent dte) { DnDUtils.debugPrintln("DropTarget dragExit"); } public void dragOver(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dragOver, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag acceptOrRejectDrag(dtde); } public void dropActionChanged(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag acceptOrRejectDrag(dtde); } public void drop(DropTargetDropEvent dtde) { DnDUtils.debugPrintln("DropTarget drop, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Check the drop action if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) { // Accept the drop and get the transfer data dtde.acceptDrop(dtde.getDropAction()); Transferable transferable = dtde.getTransferable(); try { boolean result = dropFile(transferable); dtde.dropComplete(result); DnDUtils.debugPrintln("Drop completed, success: " + result); } catch (Exception e) { DnDUtils.debugPrintln("Exception while handling drop " + e); dtde.dropComplete(false); } } else { DnDUtils.debugPrintln("Drop target rejected drop"); dtde.rejectDrop(); } } // Internal methods start here protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) { int dropAction = dtde.getDropAction(); int sourceActions = dtde.getSourceActions(); boolean acceptedDrag = false; DnDUtils.debugPrintln("\tSource actions are " + DnDUtils.showActions(sourceActions) + ", drop action is " + DnDUtils.showActions(dropAction)); // Reject if the object being transferred // or the operations available are not acceptable. if (!acceptableType || (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { // Not offering copy or move - suggest a copy DnDUtils.debugPrintln("Drop target offering COPY"); dtde.acceptDrag(DnDConstants.ACTION_COPY); acceptedDrag = true; } else { // Offering an acceptable operation: accept DnDUtils.debugPrintln("Drop target accepting drag"); dtde.acceptDrag(dropAction); acceptedDrag = true; } return acceptedDrag; } protected void checkTransferType(DropTargetDragEvent dtde) { // Only accept a list of files acceptableType = dtde .isDataFlavorSupported(DataFlavor.javaFileListFlavor); DnDUtils.debugPrintln("File type acceptable - " + acceptableType); } // This method handles a drop for a list of files protected boolean dropFile(Transferable transferable) throws IOException, UnsupportedFlavorException, MalformedURLException { List fileList = (List) transferable .getTransferData(DataFlavor.javaFileListFlavor); File transferFile = (File) fileList.get(0); final URL transferURL = transferFile.toURL(); DnDUtils.debugPrintln("File URL is " + transferURL); pane.setPage(transferURL); return true; } public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} final JFrame f = new JFrame("JEditor Pane Drop Target Example 1"); JEditorPane pane = new JEditorPane(); // Add a drop target to the JEditorPane EditorDropTarget target = new EditorDropTarget(pane); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); f.getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER); f.setSize(500, 400); f.setVisible(true); } protected JEditorPane pane; protected DropTarget dropTarget; protected boolean acceptableType; // Indicates whether data is acceptable
} class DnDUtils {
public static String showActions(int action) { String actions = ""; if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) { return "None"; } if ((action & DnDConstants.ACTION_COPY) != 0) { actions += "Copy "; } if ((action & DnDConstants.ACTION_MOVE) != 0) { actions += "Move "; } if ((action & DnDConstants.ACTION_LINK) != 0) { actions += "Link"; } return actions; } public static boolean isDebugEnabled() { return debugEnabled; } public static void debugPrintln(String s) { if (debugEnabled) { System.out.println(s); } } private static boolean debugEnabled = (System .getProperty("DnDExamples.debug") != null);
}
</source>
Editor Drop Target 2
<source lang="java">
/* Core SWING Advanced Programming By Kim Topley ISBN: 0 13 083292 8 Publisher: Prentice Hall
- /
import java.awt.BorderLayout; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import javax.swing.JCheckBox; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.UIManager; public class EditorDropTarget2 implements DropTargetListener {
public EditorDropTarget2(JEditorPane pane) { this.pane = pane; // Create the DropTarget and register // it with the JEditorPane. dropTarget = new DropTarget(pane, DnDConstants.ACTION_COPY_OR_MOVE, this, true, null); } // Implementation of the DropTargetListener interface public void dragEnter(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("dragEnter, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Get the type of object being transferred and determine // whether it is appropriate. checkTransferType(dtde); // Accept or reject the drag. acceptOrRejectDrag(dtde); } public void dragExit(DropTargetEvent dte) { DnDUtils.debugPrintln("DropTarget dragExit"); } public void dragOver(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dragOver, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag acceptOrRejectDrag(dtde); } public void dropActionChanged(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag acceptOrRejectDrag(dtde); } public void drop(DropTargetDropEvent dtde) { DnDUtils.debugPrintln("DropTarget drop, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Check the drop action if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) { // Accept the drop and get the transfer data dtde.acceptDrop(dtde.getDropAction()); Transferable transferable = dtde.getTransferable(); try { boolean result = false; if (draggingFile) { result = dropFile(transferable); } else { result = dropContent(transferable, dtde); } dtde.dropComplete(result); DnDUtils.debugPrintln("Drop completed, success: " + result); } catch (Exception e) { DnDUtils.debugPrintln("Exception while handling drop " + e); dtde.dropComplete(false); } } else { DnDUtils.debugPrintln("Drop target rejected drop"); dtde.rejectDrop(); } } // Internal methods start here protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) { int dropAction = dtde.getDropAction(); int sourceActions = dtde.getSourceActions(); boolean acceptedDrag = false; DnDUtils.debugPrintln("\tSource actions are " + DnDUtils.showActions(sourceActions) + ", drop action is " + DnDUtils.showActions(dropAction)); // Reject if the object being transferred // or the operations available are not acceptable if (!acceptableType || (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if (!draggingFile && !pane.isEditable()) { // Can"t drag text to a read-only JEditorPane DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { // Not offering copy or move - suggest a copy DnDUtils.debugPrintln("Drop target offering COPY"); dtde.acceptDrag(DnDConstants.ACTION_COPY); acceptedDrag = true; } else { // Offering an acceptable operation: accept DnDUtils.debugPrintln("Drop target accepting drag"); dtde.acceptDrag(dropAction); acceptedDrag = true; } return acceptedDrag; } protected void checkTransferType(DropTargetDragEvent dtde) { // Accept a list of files, or data content that // amounts to plain text or a Unicode text string acceptableType = false; draggingFile = false; if (DnDUtils.isDebugEnabled()) { DataFlavor[] flavors = dtde.getCurrentDataFlavors(); for (int i = 0; i < flavors.length; i++) { DataFlavor flavor = flavors[i]; DnDUtils.debugPrintln("Drop MIME type " + flavor.getMimeType() + " is available"); } } if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { acceptableType = true; draggingFile = true; } else if (dtde.isDataFlavorSupported(DataFlavor.plainTextFlavor) || dtde.isDataFlavorSupported(DataFlavor.stringFlavor)) { acceptableType = true; } DnDUtils.debugPrintln("File type acceptable - " + acceptableType); } // This method handles a drop for a list of files protected boolean dropFile(Transferable transferable) throws IOException, UnsupportedFlavorException, MalformedURLException { List fileList = (List) transferable .getTransferData(DataFlavor.javaFileListFlavor); File transferFile = (File) fileList.get(0); final URL transferURL = transferFile.toURL(); DnDUtils.debugPrintln("File URL is " + transferURL); pane.setPage(transferURL); return true; } // This method handles a drop with data content protected boolean dropContent(Transferable transferable, DropTargetDropEvent dtde) { if (!pane.isEditable()) { // Can"t drop content on a read-only text control return false; } try { // Check for a match with the current content type DataFlavor[] flavors = dtde.getCurrentDataFlavors(); DataFlavor selectedFlavor = null; // Look for either plain text or a String. for (int i = 0; i < flavors.length; i++) { DataFlavor flavor = flavors[i]; if (flavor.equals(DataFlavor.plainTextFlavor) || flavor.equals(DataFlavor.stringFlavor)) { selectedFlavor = flavor; break; } } if (selectedFlavor == null) { // No compatible flavor - should never happen return false; } DnDUtils.debugPrintln("Selected flavor is " + selectedFlavor.getHumanPresentableName()); // Get the transferable and then obtain the data Object data = transferable.getTransferData(selectedFlavor); DnDUtils.debugPrintln("Transfer data type is " + data.getClass().getName()); String insertData = null; if (data instanceof InputStream) { // Plain text flavor String charSet = selectedFlavor.getParameter("charset"); InputStream is = (InputStream) data; byte[] bytes = new byte[is.available()]; is.read(bytes); try { insertData = new String(bytes, charSet); } catch (UnsupportedEncodingException e) { // Use the platform default encoding insertData = new String(bytes); } } else if (data instanceof String) { // String flavor insertData = (String) data; } if (insertData != null) { int selectionStart = pane.getCaretPosition(); pane.replaceSelection(insertData); pane.select(selectionStart, selectionStart + insertData.length()); return true; } return false; } catch (Exception e) { return false; } } public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} final JFrame f = new JFrame("JEditor Pane Drop Target Example 2"); final JEditorPane pane = new JEditorPane(); // Add a drop target to the JEditorPane EditorDropTarget2 target = new EditorDropTarget2(pane); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); JPanel panel = new JPanel(); final JCheckBox editable = new JCheckBox("Editable"); editable.setSelected(true); panel.add(editable); editable.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { pane.setEditable(editable.isSelected()); } }); f.getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER); f.getContentPane().add(panel, BorderLayout.SOUTH); f.setSize(500, 400); f.setVisible(true); } protected JEditorPane pane; protected DropTarget dropTarget; protected boolean acceptableType; // Indicates whether data is acceptable protected boolean draggingFile; // True if dragging an entire file
} class DnDUtils {
public static String showActions(int action) { String actions = ""; if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) { return "None"; } if ((action & DnDConstants.ACTION_COPY) != 0) { actions += "Copy "; } if ((action & DnDConstants.ACTION_MOVE) != 0) { actions += "Move "; } if ((action & DnDConstants.ACTION_LINK) != 0) { actions += "Link"; } return actions; } public static boolean isDebugEnabled() { return debugEnabled; } public static void debugPrintln(String s) { if (debugEnabled) { System.out.println(s); } } private static boolean debugEnabled = (System .getProperty("DnDExamples.debug") != null);
}
</source>
Editor Drop Target 3
<source lang="java">
/* Core SWING Advanced Programming By Kim Topley ISBN: 0 13 083292 8 Publisher: Prentice Hall
- /
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Point; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import javax.swing.JCheckBox; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.UIManager; public class EditorDropTarget3 implements DropTargetListener,
PropertyChangeListener { public EditorDropTarget3(JEditorPane pane) { this.pane = pane; // Listen for changes in the enabled property pane.addPropertyChangeListener(this); // Save the JEditorPane"s background color backgroundColor = pane.getBackground(); // Create the DropTarget and register // it with the JEditorPane. dropTarget = new DropTarget(pane, DnDConstants.ACTION_COPY_OR_MOVE, this, pane.isEnabled(), null); } // Implementation of the DropTargetListener interface public void dragEnter(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("dragEnter, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Get the type of object being transferred and determine // whether it is appropriate. checkTransferType(dtde); // Accept or reject the drag. boolean acceptedDrag = acceptOrRejectDrag(dtde); // Do drag-under feedback dragUnderFeedback(dtde, acceptedDrag); } public void dragExit(DropTargetEvent dte) { DnDUtils.debugPrintln("DropTarget dragExit"); // Do drag-under feedback dragUnderFeedback(null, false); } public void dragOver(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dragOver, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag boolean acceptedDrag = acceptOrRejectDrag(dtde); // Do drag-under feedback dragUnderFeedback(dtde, acceptedDrag); } public void dropActionChanged(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag boolean acceptedDrag = acceptOrRejectDrag(dtde); // Do drag-under feedback dragUnderFeedback(dtde, acceptedDrag); } public void drop(DropTargetDropEvent dtde) { DnDUtils.debugPrintln("DropTarget drop, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Check the drop action if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) { // Accept the drop and get the transfer data dtde.acceptDrop(dtde.getDropAction()); Transferable transferable = dtde.getTransferable(); try { boolean result = false; if (draggingFile) { result = dropFile(transferable); } else { result = dropContent(transferable, dtde); } dtde.dropComplete(result); DnDUtils.debugPrintln("Drop completed, success: " + result); } catch (Exception e) { DnDUtils.debugPrintln("Exception while handling drop " + e); dtde.dropComplete(false); } } else { DnDUtils.debugPrintln("Drop target rejected drop"); dtde.rejectDrop(); } } // PropertyChangeListener interface public void propertyChange(PropertyChangeEvent evt) { String propertyName = evt.getPropertyName(); if (propertyName.equals("enabled")) { // Enable the drop target if the JEditorPane is enabled // and vice versa. dropTarget.setActive(pane.isEnabled()); } else if (!changingBackground && propertyName.equals("background")) { backgroundColor = pane.getBackground(); } } // Internal methods start here protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) { int dropAction = dtde.getDropAction(); int sourceActions = dtde.getSourceActions(); boolean acceptedDrag = false; DnDUtils.debugPrintln("\tSource actions are " + DnDUtils.showActions(sourceActions) + ", drop action is " + DnDUtils.showActions(dropAction)); // Reject if the object being transferred // or the operations available are not acceptable. if (!acceptableType || (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if (!draggingFile && !pane.isEditable()) { // Can"t drag text to a read-only JEditorPane DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { // Not offering copy or move - suggest a copy DnDUtils.debugPrintln("Drop target offering COPY"); dtde.acceptDrag(DnDConstants.ACTION_COPY); acceptedDrag = true; } else { // Offering an acceptable operation: accept DnDUtils.debugPrintln("Drop target accepting drag"); dtde.acceptDrag(dropAction); acceptedDrag = true; } return acceptedDrag; } protected void dragUnderFeedback(DropTargetDragEvent dtde, boolean acceptedDrag) { if (draggingFile) { // When dragging a file, change the background color Color newColor = (dtde != null && acceptedDrag ? feedbackColor : backgroundColor); if (newColor.equals(pane.getBackground()) == false) { changingBackground = true; pane.setBackground(newColor); changingBackground = false; pane.repaint(); } } else { if (dtde != null && acceptedDrag) { // Dragging text - move the insertion cursor Point location = dtde.getLocation(); pane.getCaret().setVisible(true); pane.setCaretPosition(pane.viewToModel(location)); } else { pane.getCaret().setVisible(false); } } } protected void checkTransferType(DropTargetDragEvent dtde) { // Accept a list of files, or data content that // amounts to plain text or a Unicode text string acceptableType = false; draggingFile = false; if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { acceptableType = true; draggingFile = true; } else if (dtde.isDataFlavorSupported(DataFlavor.plainTextFlavor) || dtde.isDataFlavorSupported(DataFlavor.stringFlavor)) { acceptableType = true; } DnDUtils.debugPrintln("File type acceptable - " + acceptableType); DnDUtils.debugPrintln("Dragging a file - " + draggingFile); } // This method handles a drop for a list of files protected boolean dropFile(Transferable transferable) throws IOException, UnsupportedFlavorException, MalformedURLException { List fileList = (List) transferable .getTransferData(DataFlavor.javaFileListFlavor); File transferFile = (File) fileList.get(0); final URL transferURL = transferFile.toURL(); DnDUtils.debugPrintln("File URL is " + transferURL); pane.setPage(transferURL); return true; } // This method handles a drop with data content protected boolean dropContent(Transferable transferable, DropTargetDropEvent dtde) { if (!pane.isEditable()) { // Can"t drop content on a read-only text control return false; } try { // Check for a match with the current content type DataFlavor[] flavors = dtde.getCurrentDataFlavors(); DataFlavor selectedFlavor = null; // Look for either plain text or a String. for (int i = 0; i < flavors.length; i++) { DataFlavor flavor = flavors[i]; DnDUtils.debugPrintln("Drop MIME type " + flavor.getMimeType() + " is available"); if (flavor.equals(DataFlavor.plainTextFlavor) || flavor.equals(DataFlavor.stringFlavor)) { selectedFlavor = flavor; break; } } if (selectedFlavor == null) { // No compatible flavor - should never happen return false; } DnDUtils.debugPrintln("Selected flavor is " + selectedFlavor.getHumanPresentableName()); // Get the transferable and then obtain the data Object data = transferable.getTransferData(selectedFlavor); DnDUtils.debugPrintln("Transfer data type is " + data.getClass().getName()); String insertData = null; if (data instanceof InputStream) { // Plain text flavor String charSet = selectedFlavor.getParameter("charset"); InputStream is = (InputStream) data; byte[] bytes = new byte[is.available()]; is.read(bytes); try { insertData = new String(bytes, charSet); } catch (UnsupportedEncodingException e) { // Use the platform default encoding insertData = new String(bytes); } } else if (data instanceof String) { // String flavor insertData = (String) data; } if (insertData != null) { int selectionStart = pane.getCaretPosition(); pane.replaceSelection(insertData); pane.select(selectionStart, selectionStart + insertData.length()); return true; } return false; } catch (Exception e) { return false; } } public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} final JFrame f = new JFrame("JEditor Pane Drop Target Example 3"); final JEditorPane pane = new JEditorPane(); // Add a drop target to the JEditorPane EditorDropTarget3 target = new EditorDropTarget3(pane); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); JPanel panel = new JPanel(); final JCheckBox editable = new JCheckBox("Editable"); editable.setSelected(true); panel.add(editable); editable.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { pane.setEditable(editable.isSelected()); } }); final JCheckBox enabled = new JCheckBox("Enabled"); enabled.setSelected(true); panel.add(enabled); enabled.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { pane.setEnabled(enabled.isSelected()); } }); f.getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER); f.getContentPane().add(panel, BorderLayout.SOUTH); f.setSize(500, 400); f.setVisible(true); } protected JEditorPane pane; protected DropTarget dropTarget; protected boolean acceptableType; // Indicates whether data is acceptable protected boolean draggingFile; // True if dragging an entire file protected Color backgroundColor; // Original background color of JEditorPane protected boolean changingBackground; protected static final Color feedbackColor = Color.gray;
} class DnDUtils {
public static String showActions(int action) { String actions = ""; if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) { return "None"; } if ((action & DnDConstants.ACTION_COPY) != 0) { actions += "Copy "; } if ((action & DnDConstants.ACTION_MOVE) != 0) { actions += "Move "; } if ((action & DnDConstants.ACTION_LINK) != 0) { actions += "Link"; } return actions; } public static boolean isDebugEnabled() { return debugEnabled; } public static void debugPrintln(String s) { if (debugEnabled) { System.out.println(s); } } private static boolean debugEnabled = (System .getProperty("DnDExamples.debug") != null);
}
</source>
Editor Drop Target 4
<source lang="java">
/* Core SWING Advanced Programming By Kim Topley ISBN: 0 13 083292 8 Publisher: Prentice Hall
- /
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.Autoscroll; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import javax.swing.JCheckBox; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; import javax.swing.UIManager; public class EditorDropTarget4 implements DropTargetListener,
PropertyChangeListener { public EditorDropTarget4(JEditorPane pane) { this.pane = pane; // Listen for changes in the enabled property pane.addPropertyChangeListener(this); // Save the JEditorPane"s background color backgroundColor = pane.getBackground(); // Create the DropTarget and register // it with the JEditorPane. dropTarget = new DropTarget(pane, DnDConstants.ACTION_COPY_OR_MOVE, this, pane.isEnabled(), null); } // Implementation of the DropTargetListener interface public void dragEnter(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("dragEnter, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Get the type of object being transferred and determine // whether it is appropriate. checkTransferType(dtde); // Accept or reject the drag. boolean acceptedDrag = acceptOrRejectDrag(dtde); // Do drag-under feedback dragUnderFeedback(dtde, acceptedDrag); } public void dragExit(DropTargetEvent dte) { DnDUtils.debugPrintln("DropTarget dragExit"); // Do drag-under feedback dragUnderFeedback(null, false); } public void dragOver(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dragOver, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag boolean acceptedDrag = acceptOrRejectDrag(dtde); // Do drag-under feedback dragUnderFeedback(dtde, acceptedDrag); } public void dropActionChanged(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag boolean acceptedDrag = acceptOrRejectDrag(dtde); // Do drag-under feedback dragUnderFeedback(dtde, acceptedDrag); } public void drop(DropTargetDropEvent dtde) { DnDUtils.debugPrintln("DropTarget drop, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Check the drop action if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) { // Accept the drop and get the transfer data dtde.acceptDrop(dtde.getDropAction()); Transferable transferable = dtde.getTransferable(); try { boolean result = false; if (draggingFile) { result = dropFile(transferable); } else { result = dropContent(transferable, dtde); } dtde.dropComplete(result); DnDUtils.debugPrintln("Drop completed, success: " + result); } catch (Exception e) { DnDUtils.debugPrintln("Exception while handling drop " + e); dtde.rejectDrop(); } } else { DnDUtils.debugPrintln("Drop target rejected drop"); dtde.dropComplete(false); } } // PropertyChangeListener interface public void propertyChange(PropertyChangeEvent evt) { String propertyName = evt.getPropertyName(); if (propertyName.equals("enabled")) { // Enable the drop target if the JEditorPane is enabled // and vice versa. dropTarget.setActive(pane.isEnabled()); } else if (!changingBackground && propertyName.equals("background")) { backgroundColor = pane.getBackground(); } } // Internal methods start here protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) { int dropAction = dtde.getDropAction(); int sourceActions = dtde.getSourceActions(); boolean acceptedDrag = false; DnDUtils.debugPrintln("\tSource actions are " + DnDUtils.showActions(sourceActions) + ", drop action is " + DnDUtils.showActions(dropAction)); // Reject if the object being transferred // or the operations available are not acceptable. if (!acceptableType || (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if (!draggingFile && !pane.isEditable()) { // Can"t drag text to a read-only JEditorPane DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { // Not offering copy or move - suggest a copy DnDUtils.debugPrintln("Drop target offering COPY"); dtde.acceptDrag(DnDConstants.ACTION_COPY); acceptedDrag = true; } else { // Offering an acceptable operation: accept DnDUtils.debugPrintln("Drop target accepting drag"); dtde.acceptDrag(dropAction); acceptedDrag = true; } return acceptedDrag; } protected void dragUnderFeedback(DropTargetDragEvent dtde, boolean acceptedDrag) { if (draggingFile) { // When dragging a file, change the background color Color newColor = (dtde != null && acceptedDrag ? feedbackColor : backgroundColor); if (newColor.equals(pane.getBackground()) == false) { changingBackground = true; pane.setBackground(newColor); changingBackground = false; pane.repaint(); } } else { if (dtde != null && acceptedDrag) { // Dragging text - move the insertion cursor Point location = dtde.getLocation(); pane.getCaret().setVisible(true); pane.setCaretPosition(pane.viewToModel(location)); } else { pane.getCaret().setVisible(false); } } } protected void checkTransferType(DropTargetDragEvent dtde) { // Accept a list of files, or data content that // amounts to plain text or a Unicode text string acceptableType = false; draggingFile = false; if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { acceptableType = true; draggingFile = true; } else if (dtde.isDataFlavorSupported(DataFlavor.plainTextFlavor) || dtde.isDataFlavorSupported(DataFlavor.stringFlavor)) { acceptableType = true; } DnDUtils.debugPrintln("File type acceptable - " + acceptableType); DnDUtils.debugPrintln("Dragging a file - " + draggingFile); } // This method handles a drop for a list of files protected boolean dropFile(Transferable transferable) throws IOException, UnsupportedFlavorException, MalformedURLException { List fileList = (List) transferable .getTransferData(DataFlavor.javaFileListFlavor); File transferFile = (File) fileList.get(0); final URL transferURL = transferFile.toURL(); DnDUtils.debugPrintln("File URL is " + transferURL); pane.setPage(transferURL); return true; } // This method handles a drop with data content protected boolean dropContent(Transferable transferable, DropTargetDropEvent dtde) { if (!pane.isEditable()) { // Can"t drop content on a read-only text control return false; } try { // Check for a match with the current content type DataFlavor[] flavors = dtde.getCurrentDataFlavors(); DataFlavor selectedFlavor = null; // Look for either plain text or a String. for (int i = 0; i < flavors.length; i++) { DataFlavor flavor = flavors[i]; DnDUtils.debugPrintln("Drop MIME type " + flavor.getMimeType() + " is available"); if (flavor.equals(DataFlavor.plainTextFlavor) || flavor.equals(DataFlavor.stringFlavor)) { selectedFlavor = flavor; break; } } if (selectedFlavor == null) { // No compatible flavor - should never happen return false; } DnDUtils.debugPrintln("Selected flavor is " + selectedFlavor.getHumanPresentableName()); // Get the transferable and then obtain the data Object data = transferable.getTransferData(selectedFlavor); DnDUtils.debugPrintln("Transfer data type is " + data.getClass().getName()); String insertData = null; if (data instanceof InputStream) { // Plain text flavor String charSet = selectedFlavor.getParameter("charset"); InputStream is = (InputStream) data; byte[] bytes = new byte[is.available()]; is.read(bytes); try { insertData = new String(bytes, charSet); } catch (UnsupportedEncodingException e) { // Use the platform default encoding insertData = new String(bytes); } } else if (data instanceof String) { // String flavor insertData = (String) data; } if (insertData != null) { int selectionStart = pane.getCaretPosition(); pane.replaceSelection(insertData); pane.select(selectionStart, selectionStart + insertData.length()); return true; } return false; } catch (Exception e) { return false; } } public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} final JFrame f = new JFrame("JEditor Pane Drop Target Example 4"); // Create an editor with autoscrolling support final JEditorPane pane = new AutoScrollingEditorPane(); // Add a drop target to the JEditorPane EditorDropTarget4 target = new EditorDropTarget4(pane); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); JPanel panel = new JPanel(); final JCheckBox editable = new JCheckBox("Editable"); editable.setSelected(true); panel.add(editable); editable.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { pane.setEditable(editable.isSelected()); } }); final JCheckBox enabled = new JCheckBox("Enabled"); enabled.setSelected(true); panel.add(enabled); enabled.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { pane.setEnabled(enabled.isSelected()); } }); f.getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER); f.getContentPane().add(panel, BorderLayout.SOUTH); f.setSize(500, 400); f.setVisible(true); } protected JEditorPane pane; protected DropTarget dropTarget; protected boolean acceptableType; // Indicates whether data is acceptable protected boolean draggingFile; // True if dragging an entire file protected Color backgroundColor; // Original background color of JEditorPane protected boolean changingBackground; protected static final Color feedbackColor = Color.gray;
} class DnDUtils {
public static String showActions(int action) { String actions = ""; if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) { return "None"; } if ((action & DnDConstants.ACTION_COPY) != 0) { actions += "Copy "; } if ((action & DnDConstants.ACTION_MOVE) != 0) { actions += "Move "; } if ((action & DnDConstants.ACTION_LINK) != 0) { actions += "Link"; } return actions; } public static boolean isDebugEnabled() { return debugEnabled; } public static void debugPrintln(String s) { if (debugEnabled) { System.out.println(s); } } private static boolean debugEnabled = (System .getProperty("DnDExamples.debug") != null);
} class AutoScrollingEditorPane extends JEditorPane implements Autoscroll {
public static final Insets defaultScrollInsets = new Insets(8, 8, 8, 8); protected Insets scrollInsets = defaultScrollInsets; public AutoScrollingEditorPane() { } public void setScrollInsets(Insets insets) { this.scrollInsets = insets; } public Insets getScrollInsets() { return scrollInsets; } // Implementation of Autoscroll interface public Insets getAutoscrollInsets() { Rectangle r = getVisibleRect(); Dimension size = getSize(); Insets i = new Insets(r.y + scrollInsets.top, r.x + scrollInsets.left, size.height - r.y - r.height + scrollInsets.bottom, size.width - r.x - r.width + scrollInsets.right); return i; } public void autoscroll(Point location) { JScrollPane scroller = (JScrollPane) SwingUtilities.getAncestorOfClass( JScrollPane.class, this); if (scroller != null) { JScrollBar hBar = scroller.getHorizontalScrollBar(); JScrollBar vBar = scroller.getVerticalScrollBar(); Rectangle r = getVisibleRect(); if (location.x <= r.x + scrollInsets.left) { // Need to scroll left hBar.setValue(hBar.getValue() - hBar.getUnitIncrement(-1)); } if (location.y <= r.y + scrollInsets.top) { // Need to scroll up vBar.setValue(vBar.getValue() - vBar.getUnitIncrement(-1)); } if (location.x >= r.x + r.width - scrollInsets.right) { // Need to scroll right hBar.setValue(hBar.getValue() + hBar.getUnitIncrement(1)); } if (location.y >= r.y + r.height - scrollInsets.bottom) { // Need to scroll down vBar.setValue(vBar.getValue() + vBar.getUnitIncrement(1)); } } }
}
</source>
Extended DnD (Drag and Drop) Demo
<source lang="java">
/* From http://java.sun.ru/docs/books/tutorial/index.html */ /*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. */
/*
* ExtendedDnDDemo.java is a 1.4 example that requires the following files: * StringTransferHandler.java ListTransferHandler.java TableTransferHandler.java */
import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.ListSelectionModel; import javax.swing.TransferHandler; import javax.swing.table.DefaultTableModel; public class ExtendedDnDDemo extends JPanel {
public ExtendedDnDDemo() { super(new GridLayout(3, 1)); add(createArea()); add(createList()); add(createTable()); } private JPanel createList() { DefaultListModel listModel = new DefaultListModel(); listModel.addElement("List 0"); listModel.addElement("List 1"); listModel.addElement("List 2"); listModel.addElement("List 3"); listModel.addElement("List 4"); listModel.addElement("List 5"); listModel.addElement("List 6"); listModel.addElement("List 7"); listModel.addElement("List 8"); JList list = new JList(listModel); list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); JScrollPane scrollPane = new JScrollPane(list); scrollPane.setPreferredSize(new Dimension(400, 100)); list.setDragEnabled(true); list.setTransferHandler(new ListTransferHandler()); JPanel panel = new JPanel(new BorderLayout()); panel.add(scrollPane, BorderLayout.CENTER); panel.setBorder(BorderFactory.createTitledBorder("List")); return panel; } private JPanel createArea() { String text = "This is the text that I want to show."; JTextArea area = new JTextArea(); area.setText(text); area.setDragEnabled(true); JScrollPane scrollPane = new JScrollPane(area); scrollPane.setPreferredSize(new Dimension(400, 100)); JPanel panel = new JPanel(new BorderLayout()); panel.add(scrollPane, BorderLayout.CENTER); panel.setBorder(BorderFactory.createTitledBorder("Text Area")); return panel; } private JPanel createTable() { DefaultTableModel model = new DefaultTableModel(); model.addColumn("Column 0"); model.addColumn("Column 1"); model.addColumn("Column 2"); model.addColumn("Column 3"); model.addRow(new String[] { "Table 00", "Table 01", "Table 02", "Table 03" }); model.addRow(new String[] { "Table 10", "Table 11", "Table 12", "Table 13" }); model.addRow(new String[] { "Table 20", "Table 21", "Table 22", "Table 23" }); model.addRow(new String[] { "Table 30", "Table 31", "Table 32", "Table 33" }); JTable table = new JTable(model); table.getTableHeader().setReorderingAllowed(false); table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); JScrollPane scrollPane = new JScrollPane(table); scrollPane.setPreferredSize(new Dimension(400, 100)); table.setDragEnabled(true); table.setTransferHandler(new TableTransferHandler()); JPanel panel = new JPanel(new BorderLayout()); panel.add(scrollPane, BorderLayout.CENTER); panel.setBorder(BorderFactory.createTitledBorder("Table")); return panel; } /** * Create the GUI and show it. For thread safety, this method should be * invoked from the event-dispatching thread. */ private static void createAndShowGUI() { //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); //Create and set up the window. JFrame frame = new JFrame("ExtendedDnDDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the content pane. JComponent newContentPane = new ExtendedDnDDemo(); newContentPane.setOpaque(true); //content panes must be opaque frame.setContentPane(newContentPane); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application"s GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); }
} /*
* ListTransferHandler.java is used by the 1.4 ExtendedDnDDemo.java example. */
class ListTransferHandler extends StringTransferHandler {
private int[] indices = null; private int addIndex = -1; //Location where items were added private int addCount = 0; //Number of items added. //Bundle up the selected items in the list //as a single string, for export. protected String exportString(JComponent c) { JList list = (JList) c; indices = list.getSelectedIndices(); Object[] values = list.getSelectedValues(); StringBuffer buff = new StringBuffer(); for (int i = 0; i < values.length; i++) { Object val = values[i]; buff.append(val == null ? "" : val.toString()); if (i != values.length - 1) { buff.append("\n"); } } return buff.toString(); } //Take the incoming string and wherever there is a //newline, break it into a separate item in the list. protected void importString(JComponent c, String str) { JList target = (JList) c; DefaultListModel listModel = (DefaultListModel) target.getModel(); int index = target.getSelectedIndex(); //Prevent the user from dropping data back on itself. //For example, if the user is moving items #4,#5,#6 and #7 and //attempts to insert the items after item #5, this would //be problematic when removing the original items. //So this is not allowed. if (indices != null && index >= indices[0] - 1 && index <= indices[indices.length - 1]) { indices = null; return; } int max = listModel.getSize(); if (index < 0) { index = max; } else { index++; if (index > max) { index = max; } } addIndex = index; String[] values = str.split("\n"); addCount = values.length; for (int i = 0; i < values.length; i++) { listModel.add(index++, values[i]); } } //If the remove argument is true, the drop has been //successful and it"s time to remove the selected items //from the list. If the remove argument is false, it //was a Copy operation and the original list is left //intact. protected void cleanup(JComponent c, boolean remove) { if (remove && indices != null) { JList source = (JList) c; DefaultListModel model = (DefaultListModel) source.getModel(); //If we are moving items around in the same list, we //need to adjust the indices accordingly, since those //after the insertion point have moved. if (addCount > 0) { for (int i = 0; i < indices.length; i++) { if (indices[i] > addIndex) { indices[i] += addCount; } } } for (int i = indices.length - 1; i >= 0; i--) { model.remove(indices[i]); } } indices = null; addCount = 0; addIndex = -1; }
} /*
* StringTransferHandler.java is used by the 1.4 ExtendedDnDDemo.java example. */
abstract class StringTransferHandler extends TransferHandler {
protected abstract String exportString(JComponent c); protected abstract void importString(JComponent c, String str); protected abstract void cleanup(JComponent c, boolean remove); protected Transferable createTransferable(JComponent c) { return new StringSelection(exportString(c)); } public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } public boolean importData(JComponent c, Transferable t) { if (canImport(c, t.getTransferDataFlavors())) { try { String str = (String) t .getTransferData(DataFlavor.stringFlavor); importString(c, str); return true; } catch (UnsupportedFlavorException ufe) { } catch (IOException ioe) { } } return false; } protected void exportDone(JComponent c, Transferable data, int action) { cleanup(c, action == MOVE); } public boolean canImport(JComponent c, DataFlavor[] flavors) { for (int i = 0; i < flavors.length; i++) { if (DataFlavor.stringFlavor.equals(flavors[i])) { return true; } } return false; }
} /*
* TableTransferHandler.java is used by the 1.4 ExtendedDnDDemo.java example. */
class TableTransferHandler extends StringTransferHandler {
private int[] rows = null; private int addIndex = -1; //Location where items were added private int addCount = 0; //Number of items added. protected String exportString(JComponent c) { JTable table = (JTable) c; rows = table.getSelectedRows(); int colCount = table.getColumnCount(); StringBuffer buff = new StringBuffer(); for (int i = 0; i < rows.length; i++) { for (int j = 0; j < colCount; j++) { Object val = table.getValueAt(rows[i], j); buff.append(val == null ? "" : val.toString()); if (j != colCount - 1) { buff.append(","); } } if (i != rows.length - 1) { buff.append("\n"); } } return buff.toString(); } protected void importString(JComponent c, String str) { JTable target = (JTable) c; DefaultTableModel model = (DefaultTableModel) target.getModel(); int index = target.getSelectedRow(); //Prevent the user from dropping data back on itself. //For example, if the user is moving rows #4,#5,#6 and #7 and //attempts to insert the rows after row #5, this would //be problematic when removing the original rows. //So this is not allowed. if (rows != null && index >= rows[0] - 1 && index <= rows[rows.length - 1]) { rows = null; return; } int max = model.getRowCount(); if (index < 0) { index = max; } else { index++; if (index > max) { index = max; } } addIndex = index; String[] values = str.split("\n"); addCount = values.length; int colCount = target.getColumnCount(); for (int i = 0; i < values.length && i < colCount; i++) { model.insertRow(index++, values[i].split(",")); } } protected void cleanup(JComponent c, boolean remove) { JTable source = (JTable) c; if (remove && rows != null) { DefaultTableModel model = (DefaultTableModel) source.getModel(); //If we are moving items around in the same table, we //need to adjust the rows accordingly, since those //after the insertion point have moved. if (addCount > 0) { for (int i = 0; i < rows.length; i++) { if (rows[i] > addIndex) { rows[i] += addCount; } } } for (int i = rows.length - 1; i >= 0; i--) { model.removeRow(rows[i]); } } rows = null; addCount = 0; addIndex = -1; }
}
</source>
File Tree Drag Source
<source lang="java">
/* Core SWING Advanced Programming By Kim Topley ISBN: 0 13 083292 8 Publisher: Prentice Hall
- /
import java.awt.Dimension; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.Autoscroll; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Arrays; import java.util.ruparator; import java.util.List; import javax.swing.JFrame; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; public class FileTreeDragSource implements DragGestureListener,
DragSourceListener { public FileTreeDragSource(FileTree tree) { this.tree = tree; // Use the default DragSource DragSource dragSource = DragSource.getDefaultDragSource(); // Create a DragGestureRecognizer and // register as the listener dragSource.createDefaultDragGestureRecognizer(tree, DnDConstants.ACTION_COPY_OR_MOVE, this); } // Implementation of DragGestureListener interface. public void dragGestureRecognized(DragGestureEvent dge) { // Get the mouse location and convert it to // a location within the tree. Point location = dge.getDragOrigin(); TreePath dragPath = tree.getPathForLocation(location.x, location.y); if (dragPath != null && tree.isPathSelected(dragPath)) { // Get the list of selected files and create a Transferable // The list of files and the is saved for use when // the drop completes. paths = tree.getSelectionPaths(); if (paths != null && paths.length > 0) { dragFiles = new File[paths.length]; for (int i = 0; i < paths.length; i++) { String pathName = tree.getPathName(paths[i]); dragFiles[i] = new File(pathName); } Transferable transferable = new FileListTransferable(dragFiles); dge.startDrag(null, transferable, this); } } } // Implementation of DragSourceListener interface public void dragEnter(DragSourceDragEvent dsde) { DnDUtils.debugPrintln("Drag Source: dragEnter, drop action = " + DnDUtils.showActions(dsde.getDropAction())); } public void dragOver(DragSourceDragEvent dsde) { DnDUtils.debugPrintln("Drag Source: dragOver, drop action = " + DnDUtils.showActions(dsde.getDropAction())); } public void dragExit(DragSourceEvent dse) { DnDUtils.debugPrintln("Drag Source: dragExit"); } public void dropActionChanged(DragSourceDragEvent dsde) { DnDUtils.debugPrintln("Drag Source: dropActionChanged, drop action = " + DnDUtils.showActions(dsde.getDropAction())); } public void dragDropEnd(DragSourceDropEvent dsde) { DnDUtils.debugPrintln("Drag Source: drop completed, drop action = " + DnDUtils.showActions(dsde.getDropAction()) + ", success: " + dsde.getDropSuccess()); // If the drop action was ACTION_MOVE, // the tree might need to be updated. if (dsde.getDropAction() == DnDConstants.ACTION_MOVE) { final File[] draggedFiles = dragFiles; final TreePath[] draggedPaths = paths; Timer tm = new Timer(200, new ActionListener() { public void actionPerformed(ActionEvent evt) { // Check whether each of the dragged files exists. // If it does not, we need to remove the node // that represents it from the tree. for (int i = 0; i < draggedFiles.length; i++) { if (draggedFiles[i].exists() == false) { // Remove this node DefaultMutableTreeNode node = (DefaultMutableTreeNode) draggedPaths[i] .getLastPathComponent(); ((DefaultTreeModel) tree.getModel()) .removeNodeFromParent(node); } } } }); tm.setRepeats(false); tm.start(); } } public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} JFrame f = new JFrame("Draggable File Tree"); try { FileTree tree = new FileTree("D:\\"); f.getContentPane().add(new JScrollPane(tree)); // Attach the drag source FileTreeDragSource dragSource = new FileTreeDragSource(tree); } catch (Exception e) { } f.pack(); f.setVisible(true); } protected FileTree tree; // The associated tree protected File[] dragFiles; // Dragged files protected TreePath[] paths; // Dragged paths
} class FileTree extends JTree implements Autoscroll {
public static final Insets defaultScrollInsets = new Insets(8, 8, 8, 8); protected Insets scrollInsets = defaultScrollInsets; public FileTree(String path) throws FileNotFoundException, SecurityException { super((TreeModel) null); // Create the JTree itself // Use horizontal and vertical lines putClientProperty("JTree.lineStyle", "Angled"); // Create the first node FileTreeNode rootNode = new FileTreeNode(null, path); // Populate the root node with its subdirectories boolean addedNodes = rootNode.populateDirectories(true); setModel(new DefaultTreeModel(rootNode)); // Listen for Tree Selection Events addTreeExpansionListener(new TreeExpansionHandler()); } // Returns the full pathname for a path, or null if not a known path public String getPathName(TreePath path) { Object o = path.getLastPathComponent(); if (o instanceof FileTreeNode) { return ((FileTreeNode) o).fullName; } return null; } // Adds a new node to the tree after construction. // Returns the inserted node, or null if the parent // directory has not been expanded. public FileTreeNode addNode(FileTreeNode parent, String name) { int index = parent.addNode(name); if (index != -1) { ((DefaultTreeModel) getModel()).nodesWereInserted(parent, new int[] { index }); return (FileTreeNode) parent.getChildAt(index); } // No node was created return null; } // Autoscrolling support public void setScrollInsets(Insets insets) { this.scrollInsets = insets; } public Insets getScrollInsets() { return scrollInsets; } // Implementation of Autoscroll interface public Insets getAutoscrollInsets() { Rectangle r = getVisibleRect(); Dimension size = getSize(); Insets i = new Insets(r.y + scrollInsets.top, r.x + scrollInsets.left, size.height - r.y - r.height + scrollInsets.bottom, size.width - r.x - r.width + scrollInsets.right); return i; } public void autoscroll(Point location) { JScrollPane scroller = (JScrollPane) SwingUtilities.getAncestorOfClass( JScrollPane.class, this); if (scroller != null) { JScrollBar hBar = scroller.getHorizontalScrollBar(); JScrollBar vBar = scroller.getVerticalScrollBar(); Rectangle r = getVisibleRect(); if (location.x <= r.x + scrollInsets.left) { // Need to scroll left hBar.setValue(hBar.getValue() - hBar.getUnitIncrement(-1)); } if (location.y <= r.y + scrollInsets.top) { // Need to scroll up vBar.setValue(vBar.getValue() - vBar.getUnitIncrement(-1)); } if (location.x >= r.x + r.width - scrollInsets.right) { // Need to scroll right hBar.setValue(hBar.getValue() + hBar.getUnitIncrement(1)); } if (location.y >= r.y + r.height - scrollInsets.bottom) { // Need to scroll down vBar.setValue(vBar.getValue() + vBar.getUnitIncrement(1)); } } } // Inner class that represents a node in this file system tree public static class FileTreeNode extends DefaultMutableTreeNode { public FileTreeNode(String parent, String name) throws SecurityException, FileNotFoundException { this.name = name; // See if this node exists and whether it is a directory fullName = parent == null ? name : parent + File.separator + name; File f = new File(fullName); if (f.exists() == false) { throw new FileNotFoundException("File " + fullName + " does not exist"); } isDir = f.isDirectory(); // Hack for Windows which doesn"t consider a drive to be a // directory! if (isDir == false && f.isFile() == false) { isDir = true; } } // Override isLeaf to check whether this is a directory public boolean isLeaf() { return !isDir; } // Override getAllowsChildren to check whether this is a directory public boolean getAllowsChildren() { return isDir; } // Return whether this is a directory public boolean isDir() { return isDir; } // Get full path public String getFullName() { return fullName; } // For display purposes, we return our own name public String toString() { return name; } // If we are a directory, scan our contents and populate // with children. In addition, populate those children // if the "descend" flag is true. We only descend once, // to avoid recursing the whole subtree. // Returns true if some nodes were added boolean populateDirectories(boolean descend) { boolean addedNodes = false; // Do this only once if (populated == false) { File f; try { f = new File(fullName); } catch (SecurityException e) { populated = true; return false; } if (interim == true) { // We have had a quick look here before: // remove the dummy node that we added last time removeAllChildren(); interim = false; } String[] names = f.list(); // Get list of contents // Process the contents ArrayList list = new ArrayList(); for (int i = 0; i < names.length; i++) { String name = names[i]; File d = new File(fullName, name); try { FileTreeNode node = new FileTreeNode(fullName, name); list.add(node); if (descend && d.isDirectory()) { node.populateDirectories(false); } addedNodes = true; if (descend == false) { // Only add one node if not descending break; } } catch (Throwable t) { // Ignore phantoms or access problems } } if (addedNodes == true) { // Now sort the list of contained files and directories Object[] nodes = list.toArray(); Arrays.sort(nodes, new Comparator() { public boolean equals(Object o) { return false; } public int compare(Object o1, Object o2) { FileTreeNode node1 = (FileTreeNode) o1; FileTreeNode node2 = (FileTreeNode) o2; // Directories come first if (node1.isDir != node2.isDir) { return node1.isDir ? -1 : +1; } // Both directories or both files - // compare based on pathname return node1.fullName.rupareTo(node2.fullName); } }); // Add sorted items as children of this node for (int j = 0; j < nodes.length; j++) { this.add((FileTreeNode) nodes[j]); } } // If we were scanning to get all subdirectories, // or if we found no content, there is no // reason to look at this directory again, so // set populated to true. Otherwise, we set interim // so that we look again in the future if we need to if (descend == true || addedNodes == false) { populated = true; } else { // Just set interim state interim = true; } } return addedNodes; } // Adding a new file or directory after // constructing the FileTree. Returns // the index of the inserted node. public int addNode(String name) { // If not populated yet, do nothing if (populated == true) { // Do not add a new node if // the required node is already there int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { FileTreeNode node = (FileTreeNode) getChildAt(i); if (node.name.equals(name)) { // Already exists - ensure // we repopulate if (node.isDir()) { node.interim = true; node.populated = false; } return -1; } } // Add a new node try { FileTreeNode node = new FileTreeNode(fullName, name); add(node); return childCount; } catch (Exception e) { } } return -1; } protected String name; // Name of this component protected String fullName; // Full pathname protected boolean populated;// true if we have been populated protected boolean interim; // true if we are in interim state protected boolean isDir; // true if this is a directory } // Inner class that handles Tree Expansion Events protected class TreeExpansionHandler implements TreeExpansionListener { public void treeExpanded(TreeExpansionEvent evt) { TreePath path = evt.getPath(); // The expanded path JTree tree = (JTree) evt.getSource(); // The tree // Get the last component of the path and // arrange to have it fully populated. FileTreeNode node = (FileTreeNode) path.getLastPathComponent(); if (node.populateDirectories(true)) { ((DefaultTreeModel) tree.getModel()).nodeStructureChanged(node); } } public void treeCollapsed(TreeExpansionEvent evt) { // Nothing to do } }
} class FileListTransferable implements Transferable {
public FileListTransferable(File[] files) { fileList = new ArrayList(); for (int i = 0; i < files.length; i++) { fileList.add(files[i]); } } // Implementation of the Transferable interface public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[] { DataFlavor.javaFileListFlavor }; } public boolean isDataFlavorSupported(DataFlavor fl) { return fl.equals(DataFlavor.javaFileListFlavor); } public Object getTransferData(DataFlavor fl) { if (!isDataFlavorSupported(fl)) { return null; } return fileList; } List fileList; // The list of files
} class DnDUtils {
public static String showActions(int action) { String actions = ""; if ((action & (DnDConstants.ACTION_LINK|DnDConstants.ACTION_COPY_OR_MOVE)) == 0) { return "None"; } if ((action & DnDConstants.ACTION_COPY) != 0) { actions += "Copy "; } if ((action & DnDConstants.ACTION_MOVE) != 0) { actions += "Move "; } if ((action & DnDConstants.ACTION_LINK) != 0) { actions += "Link"; } return actions; } public static boolean isDebugEnabled() { return debugEnabled; } public static void debugPrintln(String s) { if (debugEnabled) { System.out.println(s); } } private static boolean debugEnabled = (System.getProperty("DnDExamples.debug") != null);
}
</source>
File Tree Drop Target
<source lang="java">
/* Core SWING Advanced Programming By Kim Topley ISBN: 0 13 083292 8 Publisher: Prentice Hall
- /
import java.awt.BorderLayout; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.Autoscroll; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Arrays; import java.util.ruparator; import java.util.Iterator; import java.util.List; import java.util.Vector; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; public class FileTreeDropTarget implements DropTargetListener,
PropertyChangeListener { public FileTreeDropTarget(FileTree tree) { this.tree = tree; // Listen for changes in the enabled property tree.addPropertyChangeListener(this); // Create the DropTarget and register // it with the FileTree. dropTarget = new DropTarget(tree, DnDConstants.ACTION_COPY_OR_MOVE, this, tree.isEnabled(), null); } // Implementation of the DropTargetListener interface public void dragEnter(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("dragEnter, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Save the list of selected items saveTreeSelection(); // Get the type of object being transferred and determine // whether it is appropriate. checkTransferType(dtde); // Accept or reject the drag. boolean acceptedDrag = acceptOrRejectDrag(dtde); // Do drag-under feedback dragUnderFeedback(dtde, acceptedDrag); } public void dragExit(DropTargetEvent dte) { DnDUtils.debugPrintln("DropTarget dragExit"); // Do drag-under feedback dragUnderFeedback(null, false); // Restore the original selections restoreTreeSelection(); } public void dragOver(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dragOver, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag boolean acceptedDrag = acceptOrRejectDrag(dtde); // Do drag-under feedback dragUnderFeedback(dtde, acceptedDrag); } public void dropActionChanged(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag boolean acceptedDrag = acceptOrRejectDrag(dtde); // Do drag-under feedback dragUnderFeedback(dtde, acceptedDrag); } public void drop(DropTargetDropEvent dtde) { DnDUtils.debugPrintln("DropTarget drop, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Check the drop action if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) { // Accept the drop and get the transfer data dtde.acceptDrop(dtde.getDropAction()); Transferable transferable = dtde.getTransferable(); boolean dropSucceeded = false; try { tree.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); // Save the user"s selections saveTreeSelection(); dropSucceeded = dropFile(dtde.getDropAction(), transferable, dtde.getLocation()); DnDUtils.debugPrintln("Drop completed, success: " + dropSucceeded); } catch (Exception e) { DnDUtils.debugPrintln("Exception while handling drop " + e); } finally { tree.setCursor(Cursor.getDefaultCursor()); // Restore the user"s selections restoreTreeSelection(); dtde.dropComplete(dropSucceeded); } } else { DnDUtils.debugPrintln("Drop target rejected drop"); dtde.dropComplete(false); } } // PropertyChangeListener interface public void propertyChange(PropertyChangeEvent evt) { String propertyName = evt.getPropertyName(); if (propertyName.equals("enabled")) { // Enable the drop target if the FileTree is enabled // and vice versa. dropTarget.setActive(tree.isEnabled()); } } // Internal methods start here protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) { int dropAction = dtde.getDropAction(); int sourceActions = dtde.getSourceActions(); boolean acceptedDrag = false; DnDUtils.debugPrintln("\tSource actions are " + DnDUtils.showActions(sourceActions) + ", drop action is " + DnDUtils.showActions(dropAction)); Point location = dtde.getLocation(); boolean acceptableDropLocation = isAcceptableDropLocation(location); // Reject if the object being transferred // or the operations available are not acceptable. if (!acceptableType || (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if (!tree.isEditable()) { // Can"t drag to a read-only FileTree DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if (!acceptableDropLocation) { // Can only drag to writable directory DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { // Not offering copy or move - suggest a copy DnDUtils.debugPrintln("Drop target offering COPY"); dtde.acceptDrag(DnDConstants.ACTION_COPY); acceptedDrag = true; } else { // Offering an acceptable operation: accept DnDUtils.debugPrintln("Drop target accepting drag"); dtde.acceptDrag(dropAction); acceptedDrag = true; } return acceptedDrag; } protected void dragUnderFeedback(DropTargetDragEvent dtde, boolean acceptedDrag) { if (dtde != null && acceptedDrag) { Point location = dtde.getLocation(); if (isAcceptableDropLocation(location)) { tree.setSelectionRow( tree.getRowForLocation(location.x, location.y)); } else { tree.clearSelection(); } } else { tree.clearSelection(); } } protected void checkTransferType(DropTargetDragEvent dtde) { // Accept a list of files acceptableType = false; if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { acceptableType = true; } DnDUtils.debugPrintln("Data type acceptable - " + acceptableType); } // This method handles a drop for a list of files protected boolean dropFile(int action, Transferable transferable, Point location) throws IOException, UnsupportedFlavorException, MalformedURLException { List files = (List)transferable.getTransferData( DataFlavor.javaFileListFlavor); TreePath treePath = tree.getPathForLocation( location.x, location.y); File targetDirectory = findTargetDirectory(location); if (treePath == null || targetDirectory == null) { return false; } FileTree.FileTreeNode node = (FileTree.FileTreeNode)treePath.getLastPathComponent(); // Highlight the drop location while we perform the drop tree.setSelectionPath(treePath); // Get File objects for all files being // transferred, eliminating duplicates. File[] fileList = getFileList(files); // Don"t overwrite files by default copyOverExistingFiles = false; // Copy or move each source object to the target for (int i = 0; i < fileList.length; i++) { File f = fileList[i]; if (f.isDirectory()) { transferDirectory(action, f, targetDirectory, node); } else { try { transferFile(action, fileList[i], targetDirectory, node); } catch (IllegalStateException e) { // Cancelled by user return false; } } } return true; } protected File findTargetDirectory(Point location) { TreePath treePath = tree.getPathForLocation(location.x, location.y); if(treePath != null) { FileTree.FileTreeNode node = (FileTree.FileTreeNode)treePath.getLastPathComponent(); // Only allow a drop on a writable directory if (node.isDir()) { try { File f = new File(node.getFullName()); if (f.canWrite()) { return f; } } catch (Exception e) { } } } return null; } protected boolean isAcceptableDropLocation(Point location) { return findTargetDirectory(location) != null; } protected void saveTreeSelection() { selections = tree.getSelectionPaths(); leadSelection = tree.getLeadSelectionPath(); tree.clearSelection(); } protected void restoreTreeSelection() { tree.setSelectionPaths(selections); // Restore the lead selection if (leadSelection != null) { tree.removeSelectionPath(leadSelection); tree.addSelectionPath(leadSelection); } } // Get the list of files being transferred and // remove any duplicates. For example, if the // list contains /a/b/c and /a/b/c/d, the // second entry is removed. protected File[] getFileList(List files) { int size = files.size(); // Get the files into an array for sorting File[] f = new File[size]; Iterator iter = files.iterator(); int count = 0; while (iter.hasNext()) { f[count++] = (File)iter.next(); } // Sort the files into alphabetical order // based on pathnames. Arrays.sort(f, new Comparator() { public boolean equals(Object o1) { return false; } public int compare(Object o1, Object o2) { return ((File)o1).getAbsolutePath().rupareTo( ((File)o2).getAbsolutePath()); } }); // Remove duplicates, retaining the results in a Vector Vector v = new Vector(); char separator = System.getProperty("file.separator").charAt(0);
outer:
for (int i = f.length - 1 ; i >= 0; i--) { String secondPath = f[i].getAbsolutePath(); int secondLength = secondPath.length(); for (int j = i - 1 ; j >= 0; j--) { String firstPath = f[j].getAbsolutePath(); int firstLength = firstPath.length(); if (secondPath.startsWith(firstPath) && firstLength != secondLength && secondPath.charAt(firstLength) == separator) { continue outer; } } v.add(f[i]); } // Copy the retained files into an array f = new File[v.size()]; v.copyInto(f); return f; } // Copy or move a file protected void transferFile(int action, File srcFile, File targetDirectory, FileTree.FileTreeNode targetNode) { DnDUtils.debugPrintln( (action == DnDConstants.ACTION_COPY ? "Copy" : "Move") + " file " + srcFile.getAbsolutePath() + " to " + targetDirectory.getAbsolutePath()); // Create a File entry for the target String name = srcFile.getName(); File newFile = new File(targetDirectory, name); if (newFile.exists()) { // Already exists - is it the same file? if (newFile.equals(srcFile)) { // Exactly the same file - ignore return; } // File of this name exists in this directory if (copyOverExistingFiles == false) { int res = JOptionPane.showOptionDialog(tree, "A file called\n " + name + "\nalready exists in the directory\n " + targetDirectory.getAbsolutePath() + "\nOverwrite it?", "File Exists", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, new String[] { "Yes", "Yes to All", "No", "Cancel" }, "No"); switch (res) { case 1: // Yes to all copyOverExistingFiles = true; case 0: // Yes break; case 2: // No return; default: // Cancel throw new IllegalStateException("Cancelled"); } } } else { // New file - create it try { newFile.createNewFile(); } catch (IOException e) { JOptionPane.showMessageDialog(tree, "Failed to create new file\n " + newFile.getAbsolutePath(), "File Creation Failed", JOptionPane.ERROR_MESSAGE); return; } } // Copy the data and close file. BufferedInputStream is = null; BufferedOutputStream os = null; try { is = new BufferedInputStream( new FileInputStream(srcFile)); os = new BufferedOutputStream( new FileOutputStream(newFile)); int size = 4096; byte[] buffer = new byte[size]; int len; while ((len = is.read(buffer, 0, size)) > 0) { os.write(buffer, 0, len); } } catch (IOException e) { JOptionPane.showMessageDialog(tree, "Failed to copy file\n " + name + "\nto directory\n " + targetDirectory.getAbsolutePath(), "File Copy Failed", JOptionPane.ERROR_MESSAGE); return; } finally { try { if (is != null) { is.close(); } if (os != null) { os.close(); } } catch (IOException e) { } } // Remove the source if this is a move operation. if (action == DnDConstants.ACTION_MOVE && System.getProperty("DnDExamples.allowRemove") != null) { srcFile.delete(); } // Update the tree display if (targetNode != null) { tree.addNode(targetNode, name); } } protected void transferDirectory(int action, File srcDir, File targetDirectory, FileTree.FileTreeNode targetNode) { DnDUtils.debugPrintln( (action == DnDConstants.ACTION_COPY ? "Copy" : "Move") + " directory " + srcDir.getAbsolutePath() + " to " + targetDirectory.getAbsolutePath()); // Do not copy a directory into itself or // a subdirectory of itself. File parentDir = targetDirectory; while (parentDir != null) { if (parentDir.equals(srcDir)) { DnDUtils.debugPrintln("-- SUPPRESSED"); return; } parentDir = parentDir.getParentFile(); } // Copy the directory itself, then its contents // Create a File entry for the target String name = srcDir.getName(); File newDir = new File(targetDirectory, name); if (newDir.exists()) { // Already exists - is it the same directory? if (newDir.equals(srcDir)) { // Exactly the same file - ignore return; } } else { // Directory does not exist - create it if (newDir.mkdir() == false) { // Failed to create - abandon this directory JOptionPane.showMessageDialog(tree, "Failed to create target directory\n " + newDir.getAbsolutePath(), "Directory creation Failed", JOptionPane.ERROR_MESSAGE); return; } } // Add a node for the new directory if (targetNode != null) { targetNode = tree.addNode(targetNode, name); } // Now copy the directory content. File[] files = srcDir.listFiles(); for (int i = 0; i < files.length; i++) { File f = files[i]; if (f.isFile()) { transferFile(action, f, newDir, targetNode); } else if (f.isDirectory()) { transferDirectory(action, f, newDir, targetNode); } } // Remove the source directory after moving if (action == DnDConstants.ACTION_MOVE && System.getProperty("DnDExamples.allowRemove") != null) { srcDir.delete(); } } public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} final JFrame f = new JFrame("FileTree Drop Target Example"); try { final FileTree tree = new FileTree("D:\\"); // Add a drop target to the FileTree FileTreeDropTarget target = new FileTreeDropTarget(tree); tree.setEditable(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); JPanel panel = new JPanel(); final JCheckBox editable = new JCheckBox("Editable"); editable.setSelected(true); panel.add(editable); editable.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { tree.setEditable(editable.isSelected()); } }); final JCheckBox enabled = new JCheckBox("Enabled"); enabled.setSelected(true); panel.add(enabled); enabled.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { tree.setEnabled(enabled.isSelected()); } }); f.getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER); f.getContentPane().add(panel, BorderLayout.SOUTH); f.setSize(500, 400); f.setVisible(true); } catch (Exception e) { System.out.println("Failed to build GUI: " + e); } } protected FileTree tree; protected DropTarget dropTarget; protected boolean acceptableType; // Indicates whether data is acceptable TreePath[] selections; // Initially selected rows TreePath leadSelection; // Initial lead selection boolean copyOverExistingFiles;
}
class FileTree extends JTree implements Autoscroll {
public static final Insets defaultScrollInsets = new Insets(8, 8, 8, 8); protected Insets scrollInsets = defaultScrollInsets; public FileTree(String path) throws FileNotFoundException, SecurityException { super((TreeModel)null); // Create the JTree itself // Use horizontal and vertical lines putClientProperty("JTree.lineStyle", "Angled"); // Create the first node FileTreeNode rootNode = new FileTreeNode(null, path); // Populate the root node with its subdirectories boolean addedNodes = rootNode.populateDirectories(true); setModel(new DefaultTreeModel(rootNode)); // Listen for Tree Selection Events addTreeExpansionListener(new TreeExpansionHandler()); } // Returns the full pathname for a path, or null if not a known path public String getPathName(TreePath path) { Object o = path.getLastPathComponent(); if (o instanceof FileTreeNode) { return ((FileTreeNode)o).fullName; } return null; } // Adds a new node to the tree after construction. // Returns the inserted node, or null if the parent // directory has not been expanded. public FileTreeNode addNode(FileTreeNode parent, String name) { int index = parent.addNode(name); if (index != -1) { ((DefaultTreeModel)getModel()).nodesWereInserted( parent, new int[] { index }); return (FileTreeNode)parent.getChildAt(index); } // No node was created return null; } // Autoscrolling support public void setScrollInsets(Insets insets) { this.scrollInsets = insets; } public Insets getScrollInsets() { return scrollInsets; } // Implementation of Autoscroll interface public Insets getAutoscrollInsets() { Rectangle r = getVisibleRect(); Dimension size = getSize(); Insets i = new Insets(r.y + scrollInsets.top, r.x + scrollInsets.left, size.height - r.y - r.height + scrollInsets.bottom, size.width - r.x - r.width + scrollInsets.right); return i; } public void autoscroll(Point location) { JScrollPane scroller = (JScrollPane)SwingUtilities.getAncestorOfClass(JScrollPane.class, this); if (scroller != null) { JScrollBar hBar = scroller.getHorizontalScrollBar(); JScrollBar vBar = scroller.getVerticalScrollBar(); Rectangle r = getVisibleRect(); if (location.x <= r.x + scrollInsets.left) { // Need to scroll left hBar.setValue(hBar.getValue() - hBar.getUnitIncrement(-1)); } if (location.y <= r.y + scrollInsets.top) { // Need to scroll up vBar.setValue(vBar.getValue() - vBar.getUnitIncrement(-1)); } if (location.x >= r.x + r.width - scrollInsets.right) { // Need to scroll right hBar.setValue(hBar.getValue() + hBar.getUnitIncrement(1)); } if (location.y >= r.y + r.height - scrollInsets.bottom) { // Need to scroll down vBar.setValue(vBar.getValue() + vBar.getUnitIncrement(1)); } } } // Inner class that represents a node in this file system tree public static class FileTreeNode extends DefaultMutableTreeNode { public FileTreeNode(String parent, String name) throws SecurityException, FileNotFoundException { this.name = name; // See if this node exists and whether it is a directory fullName = parent == null ? name : parent + File.separator + name; File f = new File(fullName); if (f.exists() == false) { throw new FileNotFoundException("File " + fullName + " does not exist"); } isDir = f.isDirectory(); // Hack for Windows which doesn"t consider a drive to be a directory! if (isDir == false && f.isFile() == false) { isDir = true; } } // Override isLeaf to check whether this is a directory public boolean isLeaf() { return !isDir; } // Override getAllowsChildren to check whether this is a directory public boolean getAllowsChildren() { return isDir; } // Return whether this is a directory public boolean isDir() { return isDir; } // Get full path public String getFullName() { return fullName; } // For display purposes, we return our own name public String toString() { return name; } // If we are a directory, scan our contents and populate // with children. In addition, populate those children // if the "descend" flag is true. We only descend once, // to avoid recursing the whole subtree. // Returns true if some nodes were added boolean populateDirectories(boolean descend) { boolean addedNodes = false; // Do this only once if (populated == false) { File f; try { f = new File(fullName); } catch (SecurityException e) { populated = true; return false; } if (interim == true) { // We have had a quick look here before: // remove the dummy node that we added last time removeAllChildren(); interim = false; } String[] names = f.list(); // Get list of contents // Process the contents ArrayList list = new ArrayList(); for (int i = 0; i < names.length; i++) { String name = names[i]; File d = new File(fullName, name); try { FileTreeNode node = new FileTreeNode(fullName, name); list.add(node); if (descend && d.isDirectory()) { node.populateDirectories(false); } addedNodes = true; if (descend == false) { // Only add one node if not descending break; } } catch (Throwable t) { // Ignore phantoms or access problems } } if (addedNodes == true) { // Now sort the list of contained files and directories Object[] nodes = list.toArray(); Arrays.sort(nodes, new Comparator() { public boolean equals(Object o) { return false; } public int compare(Object o1, Object o2) { FileTreeNode node1 = (FileTreeNode)o1; FileTreeNode node2 = (FileTreeNode)o2; // Directories come first if (node1.isDir != node2.isDir) { return node1.isDir ? -1 : +1; } // Both directories or both files - // compare based on pathname return node1.fullName.rupareTo(node2.fullName); } }); // Add sorted items as children of this node for (int j = 0; j < nodes.length; j++) { this.add((FileTreeNode)nodes[j]); } } // If we were scanning to get all subdirectories, // or if we found no content, there is no // reason to look at this directory again, so // set populated to true. Otherwise, we set interim // so that we look again in the future if we need to if (descend == true || addedNodes == false) { populated = true; } else { // Just set interim state interim = true; } } return addedNodes; } // Adding a new file or directory after // constructing the FileTree. Returns // the index of the inserted node. public int addNode(String name) { // If not populated yet, do nothing if (populated == true) { // Do not add a new node if // the required node is already there int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { FileTreeNode node = (FileTreeNode)getChildAt(i); if (node.name.equals(name)) { // Already exists - ensure // we repopulate if (node.isDir()) { node.interim = true; node.populated = false; } return -1; } } // Add a new node try { FileTreeNode node = new FileTreeNode(fullName, name); add(node); return childCount; } catch (Exception e) { } } return -1; } protected String name; // Name of this component protected String fullName; // Full pathname protected boolean populated;// true if we have been populated protected boolean interim; // true if we are in interim state protected boolean isDir; // true if this is a directory } // Inner class that handles Tree Expansion Events protected class TreeExpansionHandler implements TreeExpansionListener { public void treeExpanded(TreeExpansionEvent evt) { TreePath path = evt.getPath(); // The expanded path JTree tree = (JTree)evt.getSource(); // The tree // Get the last component of the path and // arrange to have it fully populated. FileTreeNode node = (FileTreeNode)path.getLastPathComponent(); if (node.populateDirectories(true)) { ((DefaultTreeModel)tree.getModel()).nodeStructureChanged(node); } } public void treeCollapsed(TreeExpansionEvent evt) { // Nothing to do } }
} class DnDUtils {
public static String showActions(int action) { String actions = ""; if ((action & (DnDConstants.ACTION_LINK|DnDConstants.ACTION_COPY_OR_MOVE)) == 0) { return "None"; } if ((action & DnDConstants.ACTION_COPY) != 0) { actions += "Copy "; } if ((action & DnDConstants.ACTION_MOVE) != 0) { actions += "Move "; } if ((action & DnDConstants.ACTION_LINK) != 0) { actions += "Link"; } return actions; } public static boolean isDebugEnabled() { return debugEnabled; } public static void debugPrintln(String s) { if (debugEnabled) { System.out.println(s); } } private static boolean debugEnabled = (System.getProperty("DnDExamples.debug") != null);
}
</source>
Getting and Setting Text on the System Clipboard
<source lang="java">
import java.awt.Toolkit; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; public class Main {
public static void main(String[] argv) throws Exception { Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null); if (t != null && t.isDataFlavorSupported(DataFlavor.stringFlavor)) { String text = (String) t.getTransferData(DataFlavor.stringFlavor); System.out.println(text); } }
}
</source>
Implement drag & drop functionality in your application
<source lang="java">
import java.awt.BorderLayout; import java.awt.Color; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextArea; public class Main extends JFrame implements DropTargetListener {
DropTarget dt; JTextArea ta = new JTextArea(); public Main() { super("Drop Test"); setSize(300, 300); getContentPane() .add(new JLabel("Drop something here:"), BorderLayout.NORTH); ta.setBackground(Color.white); getContentPane().add(ta, BorderLayout.CENTER); dt = new DropTarget(ta, this); setVisible(true); } public void dragEnter(DropTargetDragEvent dtde) { System.out.println("Drag Enter"); } public void dragExit(DropTargetEvent dte) { System.out.println("Drag Exit"); } public void dragOver(DropTargetDragEvent dtde) { System.out.println("Drag Over"); } public void dropActionChanged(DropTargetDragEvent dtde) { System.out.println("Drop Action Changed"); } public void drop(DropTargetDropEvent dtde) { try { Transferable tr = dtde.getTransferable(); DataFlavor[] flavors = tr.getTransferDataFlavors(); for (int i = 0; i < flavors.length; i++) { if (flavors[i].isFlavorJavaFileListType()) { dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); List list = (List) tr.getTransferData(flavors[i]); for (int j = 0; j < list.size(); j++) { ta.append(list.get(j) + "\n"); } dtde.dropComplete(true); return; } else if (flavors[i].isFlavorSerializedObjectType()) { dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); Object o = tr.getTransferData(flavors[i]); ta.append("Object: " + o); dtde.dropComplete(true); return; } else if (flavors[i].isRepresentationClassInputStream()) { dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); ta.read(new InputStreamReader((InputStream) tr.getTransferData(flavors[i])), "from system clipboard"); dtde.dropComplete(true); return; } } dtde.rejectDrop(); } catch (Exception e) { e.printStackTrace(); dtde.rejectDrop(); } } public static void main(String args[]) { new Main(); }
}
</source>
implements DragGestureListener, Transferable
<source lang="java">
import java.awt.Cursor; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import javax.swing.JFrame; import javax.swing.JLabel; public class DragGesture extends JFrame implements DragGestureListener, Transferable {
public DragGesture() { setTitle("Drag Gesture"); JLabel left = new JLabel("text"); DragSource ds = new DragSource(); ds.createDefaultDragGestureRecognizer(left, DnDConstants.ACTION_COPY, this); add(left); pack(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public void dragGestureRecognized(DragGestureEvent event) { Cursor cursor = null; if (event.getDragAction() == DnDConstants.ACTION_COPY) { cursor = DragSource.DefaultCopyDrop; } event.startDrag(cursor, this); } public Object getTransferData(DataFlavor flavor) { return null; } public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[0]; } public boolean isDataFlavorSupported(DataFlavor flavor) { return false; } public static void main(String[] args) { new DragGesture(); }
}
</source>
JLabel Drag Source
<source lang="java">
/* Core SWING Advanced Programming By Kim Topley ISBN: 0 13 083292 8 Publisher: Prentice Hall
- /
import java.awt.Font; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Iterator; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.UIManager; public class JLabelDragSource implements DragGestureListener,
DragSourceListener { public JLabelDragSource(JLabel label) { this.label = label; // Use the default DragSource DragSource dragSource = DragSource.getDefaultDragSource(); // Create a DragGestureRecognizer and // register as the listener dragSource.createDefaultDragGestureRecognizer(label, DnDConstants.ACTION_COPY_OR_MOVE, this); } // Implementation of DragGestureListener interface. public void dragGestureRecognized(DragGestureEvent dge) { if (DnDUtils.isDebugEnabled()) { DnDUtils.debugPrintln("Initiating event is " + dge.getTriggerEvent()); DnDUtils.debugPrintln("Complete event set is:"); Iterator iter = dge.iterator(); while (iter.hasNext()) { DnDUtils.debugPrintln("\t" + iter.next()); } } Transferable transferable = new JLabelTransferable(label); dge.startDrag(null, transferable, this); } // Implementation of DragSourceListener interface public void dragEnter(DragSourceDragEvent dsde) { DnDUtils.debugPrintln("Drag Source: dragEnter, drop action = " + DnDUtils.showActions(dsde.getDropAction())); } public void dragOver(DragSourceDragEvent dsde) { DnDUtils.debugPrintln("Drag Source: dragOver, drop action = " + DnDUtils.showActions(dsde.getDropAction())); } public void dragExit(DragSourceEvent dse) { DnDUtils.debugPrintln("Drag Source: dragExit"); } public void dropActionChanged(DragSourceDragEvent dsde) { DnDUtils.debugPrintln("Drag Source: dropActionChanged, drop action = " + DnDUtils.showActions(dsde.getDropAction())); } public void dragDropEnd(DragSourceDropEvent dsde) { DnDUtils.debugPrintln("Drag Source: drop completed, drop action = " + DnDUtils.showActions(dsde.getDropAction()) + ", success: " + dsde.getDropSuccess()); } public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} JFrame f = new JFrame("Draggable JLabel"); JLabel label = new JLabel("Drag this text", JLabel.CENTER); label.setFont(new Font("Serif", Font.BOLD, 32)); f.getContentPane().add(label); f.pack(); f.setVisible(true); // Attach the drag source JLabelDragSource dragSource = new JLabelDragSource(label); } protected JLabel label; // The associated JLabel
} class DnDUtils {
public static String showActions(int action) { String actions = ""; if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) { return "None"; } if ((action & DnDConstants.ACTION_COPY) != 0) { actions += "Copy "; } if ((action & DnDConstants.ACTION_MOVE) != 0) { actions += "Move "; } if ((action & DnDConstants.ACTION_LINK) != 0) { actions += "Link"; } return actions; } public static boolean isDebugEnabled() { return debugEnabled; } public static void debugPrintln(String s) { if (debugEnabled) { System.out.println(s); } } private static boolean debugEnabled = (System .getProperty("DnDExamples.debug") != null);
} class JLabelTransferable implements Transferable {
public JLabelTransferable(JLabel label) { this.label = label; } // Implementation of the Transferable interface public DataFlavor[] getTransferDataFlavors() { return flavors; } public boolean isDataFlavorSupported(DataFlavor fl) { for (int i = 0; i < flavors.length; i++) { if (fl.equals(flavors[i])) { return true; } } return false; } public Object getTransferData(DataFlavor fl) { if (!isDataFlavorSupported(fl)) { return null; } if (fl.equals(DataFlavor.stringFlavor)) { // String - return the text as a String return label.getText() + " (DataFlavor.stringFlavor)"; } else if (fl.equals(jLabelFlavor)) { // The JLabel itself - just return the label. return label; } else { // Plain text - return an InputStream try { String targetText = label.getText() + " (plain text flavor)"; int length = targetText.length(); ByteArrayOutputStream os = new ByteArrayOutputStream(); OutputStreamWriter w = new OutputStreamWriter(os); w.write(targetText, 0, length); w.flush(); byte[] bytes = os.toByteArray(); w.close(); return new ByteArrayInputStream(bytes); } catch (IOException e) { return null; } } } // A flavor that transfers a copy of the JLabel public static final DataFlavor jLabelFlavor = new DataFlavor(JLabel.class, "Swing JLabel"); private JLabel label; // The label being transferred private static final DataFlavor[] flavors = new DataFlavor[] { DataFlavor.stringFlavor, new DataFlavor("text/plain; charset=ascii", "ASCII text"), jLabelFlavor };
}
</source>
JTextArea subclass allows TransferableColor objects to
<source lang="java">
/*
* This example is from the book "Java Foundation Classes in a Nutshell". * Written by David Flanagan. Copyright (c) 1999 by O"Reilly & Associates. * You may distribute this source code for non-commercial purposes only. * You may study, modify, and use this example for any purpose, as long as * this notice is retained. Note that this example is provided "as is", * WITHOUT WARRANTY of any kind either expressed or implied. */
import java.awt.*; import java.awt.event.*; import java.awt.datatransfer.*; import java.awt.dnd.*; import javax.swing.*; import javax.swing.border.*; import java.io.*; import java.util.List; /**
* This simple JTextArea subclass allows TransferableColor objects to * be pasted or dropped into it. It also supports the pasting of * text, and the dropping of File objects. */
public class ColorSink extends JTextArea implements DropTargetListener {
/** Create a new ColorSink object */ public ColorSink() { // Listen for double clicks. Use them to trigger a paste action. addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { pastecolor(); e.consume(); } } }); // We have to create a DropTarget object to support Drag-and-Drop // It will listen for drops on top of us, and notify our DropTargetListener // methods when drag-and-drop related events occur. setDropTarget(new DropTarget(this, this)); } // This method is invoked when the user double-clicks on us. It attempts // to paste a color or text. Note that the JTextArea we extend // already supports cut-and-paste of text through the Ctrl-V keystroke. // This adds a different kind of cut-and-paste for demonstration purposes. public void pastecolor() { // Get the clipboard, and read its contents Clipboard c = this.getToolkit().getSystemClipboard(); Transferable t = c.getContents(this); if (t == null) { // If nothing to paste this.getToolkit().beep(); // then beep and do nothing return; } try { // If the clipboard contained a color, use it as the background color if (t.isDataFlavorSupported(TransferableColor.colorFlavor)) { Color color = (Color) t.getTransferData(TransferableColor.colorFlavor); this.setBackground(color); } // If the clipboard contained text, insert it. else if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) { String s = (String) t.getTransferData(DataFlavor.stringFlavor); this.replaceSelection(s); } // Otherwise, we don"t know how to paste the data, so just beep. else this.getToolkit().beep(); } catch (UnsupportedFlavorException ex) { this.getToolkit().beep(); } catch (IOException ex) { this.getToolkit().beep(); } } // The methods below are the methods of DropTargetListener. // They are invoked at various times when something is being // dragged over us, and allow us an opportunity to respond to the drag // This is the border we display when the user is dragging over us. protected static Border dropBorder = new BevelBorder(BevelBorder.LOWERED); // Something is being dragged over us. If we can support this data type // tell the drag-and-drop system that we are interested, and display // a special border to tell the user that we"re intereted. public void dragEnter(DropTargetDragEvent e) { if (e.isDataFlavorSupported(TransferableColor.colorFlavor) || e.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE); this.setBorder(dropBorder); } } /** The user is no longer dragging over us, so restore the default border */ public void dragExit(DropTargetEvent e) { this.setBorder(null); } /** This method is invoked when the user drops something on us */ public void drop(DropTargetDropEvent e){ this.setBorder(null); // Restore the default border Transferable t = e.getTransferable(); // Get the data that was dropped // Check for types of data that we support if (t.isDataFlavorSupported(TransferableColor.colorFlavor)) { // If it was a color, accept it, and use it as the background color e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); try { Color c = (Color) t.getTransferData(TransferableColor.colorFlavor); this.setBackground(c); e.dropComplete(true); } catch (Exception ex) { e.dropComplete(false); } } else if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { // If it was a file list, accept it, read the first file in the list // and display the file contents e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); try { List files = (List) t.getTransferData(DataFlavor.javaFileListFlavor); File f = (File) files.get(0); BufferedReader in = new BufferedReader(new FileReader(f)); String s; this.setText(""); while((s = in.readLine()) != null) this.append(s); e.dropComplete(true); } catch (Exception ex) { e.dropComplete(false); } } else { // If it wasn"t a color or a file list, reject it. e.rejectDrop(); return; } } // These are unused DropTargetListener methods public void dragOver(DropTargetDragEvent e) {} public void dropActionChanged(DropTargetDragEvent e) {} /** This is a simple test program for ColorSource and ColorSink */ public static void main(String[] args) { // Create a window JFrame f = new JFrame("ColorSourceTest"); f.getContentPane().setLayout(new BorderLayout()); // Add some ColorSources JPanel panel = new JPanel(); f.getContentPane().add(panel, BorderLayout.NORTH); panel.add(new ColorSource(Color.yellow)); panel.add(new ColorSource(Color.pink)); panel.add(new ColorSource(Color.white)); panel.add(new ColorSource(Color.gray)); // Add a ColorSink ColorSink sink = new ColorSink(); f.getContentPane().add(sink, BorderLayout.CENTER); // Pop it all up f.setSize(400, 300); f.show(); }
}
</source>
LabelDnD2 allows dropping color onto the foreground of the JLabel
<source lang="java">
/* From http://java.sun.ru/docs/books/tutorial/index.html */ /*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. */
/*
* LabelDnD2.java is a 1.4 example that requires no other files. */
import java.awt.BorderLayout; import java.awt.GridLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.BorderFactory; import javax.swing.JColorChooser; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.TransferHandler; import javax.swing.border.TitledBorder; //LabelDnD2 allows dropping color onto the foreground //of the JLabel. public class LabelDnD2 extends JPanel {
JTextField textField; JLabel label; public LabelDnD2() { super(new BorderLayout()); JColorChooser chooser = new JColorChooser(); chooser.setDragEnabled(true); label = new JLabel("I"m a Label and I accept color!", SwingConstants.LEADING); label.setTransferHandler(new TransferHandler("foreground")); MouseListener listener = new DragMouseAdapter(); label.addMouseListener(listener); JPanel lpanel = new JPanel(new GridLayout(1, 1)); TitledBorder t2 = BorderFactory .createTitledBorder("JLabel: drop color onto the label"); lpanel.add(label); lpanel.setBorder(t2); add(chooser, BorderLayout.CENTER); add(lpanel, BorderLayout.PAGE_END); setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); } private class DragMouseAdapter extends MouseAdapter { public void mousePressed(MouseEvent e) { JComponent c = (JComponent) e.getSource(); TransferHandler handler = c.getTransferHandler(); handler.exportAsDrag(c, e, TransferHandler.COPY); } } /** * Create the GUI and show it. For thread safety, this method should be * invoked from the event-dispatching thread. */ private static void createAndShowGUI() { //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); //Create and set up the window. JFrame frame = new JFrame("LabelDnD2"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the content pane. JComponent newContentPane = new LabelDnD2(); newContentPane.setOpaque(true); //content panes must be opaque frame.setContentPane(newContentPane); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application"s GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); }
}
</source>
Label DnD (Drag and Drop)
<source lang="java">
/* From http://java.sun.ru/docs/books/tutorial/index.html */ /*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. */
/*
* LabelDnD.java is a 1.4 example that requires no other files. */
import java.awt.GridLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.TransferHandler; import javax.swing.border.TitledBorder; public class LabelDnD extends JPanel {
JTextField textField; JLabel label; public LabelDnD() { super(new GridLayout(2, 1)); textField = new JTextField(40); textField.setDragEnabled(true); JPanel tfpanel = new JPanel(new GridLayout(1, 1)); TitledBorder t1 = BorderFactory .createTitledBorder("JTextField: drag and drop is enabled"); tfpanel.add(textField); tfpanel.setBorder(t1); label = new JLabel("I"m a Label!", SwingConstants.LEADING); label.setTransferHandler(new TransferHandler("text")); MouseListener listener = new DragMouseAdapter(); label.addMouseListener(listener); JPanel lpanel = new JPanel(new GridLayout(1, 1)); TitledBorder t2 = BorderFactory .createTitledBorder("JLabel: drag from or drop to this label"); lpanel.add(label); lpanel.setBorder(t2); add(tfpanel); add(lpanel); setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); } private class DragMouseAdapter extends MouseAdapter { public void mousePressed(MouseEvent e) { JComponent c = (JComponent) e.getSource(); TransferHandler handler = c.getTransferHandler(); handler.exportAsDrag(c, e, TransferHandler.COPY); } } /** * Create the GUI and show it. For thread safety, this method should be * invoked from the event-dispatching thread. */ private static void createAndShowGUI() { //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); //Create and set up the window. JFrame frame = new JFrame("LabelDnD"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the content pane. JComponent newContentPane = new LabelDnD(); newContentPane.setOpaque(true); //content panes must be opaque frame.setContentPane(newContentPane); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application"s GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); }
}
</source>
Making a Component Draggable
<source lang="java">
import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import javax.swing.JComponent; import javax.swing.JFrame; public class Main {
public static void main(String[] argv) throws Exception { JComponent com = new DraggableComponent(); JFrame f = new JFrame(); f.add(com); f.setSize(300, 300); f.setVisible(true); }
} class DraggableComponent extends JComponent implements DragGestureListener, DragSourceListener {
DragSource dragSource; public DraggableComponent() { dragSource = new DragSource(); dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, this); } public void dragGestureRecognized(DragGestureEvent evt) { Transferable t = new StringSelection("aString"); dragSource.startDrag(evt, DragSource.DefaultCopyDrop, t, this); } public void dragEnter(DragSourceDragEvent evt) { System.out.println("enters"); } public void dragOver(DragSourceDragEvent evt) { System.out.println("over"); } public void dragExit(DragSourceEvent evt) { System.out.println("leaves"); } public void dropActionChanged(DragSourceDragEvent evt) { System.out.println("changes the drag action between copy or move"); } public void dragDropEnd(DragSourceDropEvent evt) { System.out.println("finishes or cancels the drag operation"); }
}
</source>
Panel Drop Target
<source lang="java">
/* Core SWING Advanced Programming By Kim Topley ISBN: 0 13 083292 8 Publisher: Prentice Hall
- /
import java.awt.BorderLayout; import java.awt.ruponent; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.UIManager; public class PanelDropTarget implements DropTargetListener {
public PanelDropTarget(JPanel pane) { this.pane = pane; // Create the DropTarget and register // it with the JPanel. dropTarget = new DropTarget(pane, DnDConstants.ACTION_COPY_OR_MOVE, this, true, null); } // Implementation of the DropTargetListener interface public void dragEnter(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("dragEnter, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Get the type of object being transferred and determine // whether it is appropriate. checkTransferType(dtde); // Accept or reject the drag. acceptOrRejectDrag(dtde); } public void dragExit(DropTargetEvent dte) { DnDUtils.debugPrintln("DropTarget dragExit"); } public void dragOver(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dragOver, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag acceptOrRejectDrag(dtde); } public void dropActionChanged(DropTargetDragEvent dtde) { DnDUtils.debugPrintln("DropTarget dropActionChanged, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Accept or reject the drag acceptOrRejectDrag(dtde); } public void drop(DropTargetDropEvent dtde) { DnDUtils.debugPrintln("DropTarget drop, drop action = " + DnDUtils.showActions(dtde.getDropAction())); // Check the drop action if ((dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0) { // Accept the drop and get the transfer data dtde.acceptDrop(dtde.getDropAction()); Transferable transferable = dtde.getTransferable(); try { boolean result = dropComponent(transferable); dtde.dropComplete(result); DnDUtils.debugPrintln("Drop completed, success: " + result); } catch (Exception e) { DnDUtils.debugPrintln("Exception while handling drop " + e); dtde.dropComplete(false); } } else { DnDUtils.debugPrintln("Drop target rejected drop"); dtde.rejectDrop(); } } // Internal methods start here protected boolean acceptOrRejectDrag(DropTargetDragEvent dtde) { int dropAction = dtde.getDropAction(); int sourceActions = dtde.getSourceActions(); boolean acceptedDrag = false; DnDUtils.debugPrintln("\tSource actions are " + DnDUtils.showActions(sourceActions) + ", drop action is " + DnDUtils.showActions(dropAction)); // Reject if the object being transferred // or the operations available are not acceptable. if (!acceptableType || (sourceActions & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { DnDUtils.debugPrintln("Drop target rejecting drag"); dtde.rejectDrag(); } else if ((dropAction & DnDConstants.ACTION_COPY_OR_MOVE) == 0) { // Not offering copy or move - suggest a copy DnDUtils.debugPrintln("Drop target offering COPY"); dtde.acceptDrag(DnDConstants.ACTION_COPY); acceptedDrag = true; } else { // Offering an acceptable operation: accept DnDUtils.debugPrintln("Drop target accepting drag"); dtde.acceptDrag(dropAction); acceptedDrag = true; } return acceptedDrag; } protected void checkTransferType(DropTargetDragEvent dtde) { // Only accept a flavor that returns a Component acceptableType = false; DataFlavor[] fl = dtde.getCurrentDataFlavors(); for (int i = 0; i < fl.length; i++) { Class dataClass = fl[i].getRepresentationClass(); if (Component.class.isAssignableFrom(dataClass)) { // This flavor returns a Component - accept it. targetFlavor = fl[i]; acceptableType = true; break; } } DnDUtils.debugPrintln("File type acceptable - " + acceptableType); } protected boolean dropComponent(Transferable transferable) throws IOException, UnsupportedFlavorException { Object o = transferable.getTransferData(targetFlavor); if (o instanceof Component) { DnDUtils.debugPrintln("Dragged component class is " + o.getClass().getName()); pane.add((Component) o); pane.validate(); return true; } return false; } public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} final JFrame f = new JFrame("Component drop target example"); JPanel pane = new JPanel(); // Add a drop target to the JPanel PanelDropTarget target = new PanelDropTarget(pane); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { System.exit(0); } }); f.getContentPane().add(new JScrollPane(pane), BorderLayout.CENTER); f.setSize(500, 400); f.setVisible(true); } protected JPanel pane; protected DropTarget dropTarget; protected boolean acceptableType; // Indicates whether data is acceptable protected DataFlavor targetFlavor; // Flavor to use for transfer
} class DnDUtils {
public static String showActions(int action) { String actions = ""; if ((action & (DnDConstants.ACTION_LINK | DnDConstants.ACTION_COPY_OR_MOVE)) == 0) { return "None"; } if ((action & DnDConstants.ACTION_COPY) != 0) { actions += "Copy "; } if ((action & DnDConstants.ACTION_MOVE) != 0) { actions += "Move "; } if ((action & DnDConstants.ACTION_LINK) != 0) { actions += "Link"; } return actions; } public static boolean isDebugEnabled() { return debugEnabled; } public static void debugPrintln(String s) { if (debugEnabled) { System.out.println(s); } } private static boolean debugEnabled = (System .getProperty("DnDExamples.debug") != null);
}
</source>
Setting text drag in a JTextArea
<source lang="java">
import java.awt.BorderLayout; import javax.swing.JFrame; import javax.swing.JTextArea; import javax.swing.JTextField; public class Main {
public static void main(String[] args) { JFrame frame = new JFrame(); JTextArea textarea = new JTextArea(); textarea.setDragEnabled(true); textarea.setText("Drag target"); frame.getContentPane().add(BorderLayout.CENTER, textarea); JTextField textarea1 = new JTextField(); textarea1.setText("Drop target"); frame.getContentPane().add(BorderLayout.SOUTH, textarea1); frame.setSize(500, 300); frame.setVisible(true); frame.setLocation(100, 100); }
}
</source>
Test of the DragGesture classes and JList to see if we
<source lang="java">
/* Java Swing, 2nd Edition By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole ISBN: 0-596-00408-7 Publisher: O"Reilly
- /
// GestureTest.java //A simple (?) test of the DragGesture classes to see if we //can recognize a simple drag gesture. // import java.awt.BorderLayout; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragGestureRecognizer; import java.awt.dnd.DragSource; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; public class GestureTest extends JFrame implements DragGestureListener {
DragSource ds; JList jl; String[] items = { "Java", "C", "C++", "Lisp", "Perl", "Python" }; public GestureTest() { super("Gesture Test"); setSize(200, 150); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { System.exit(0); } }); jl = new JList(items); jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); getContentPane().add(new JScrollPane(jl), BorderLayout.CENTER); ds = new DragSource(); DragGestureRecognizer dgr = ds.createDefaultDragGestureRecognizer(jl, DnDConstants.ACTION_COPY, this); setVisible(true); } public void dragGestureRecognized(DragGestureEvent dge) { System.out.println("Drag Gesture Recognized!"); } public static void main(String args[]) { new GestureTest(); }
}
</source>
Transferable Color
<source lang="java">
/*
* This example is from the book "Java Foundation Classes in a Nutshell". * Written by David Flanagan. Copyright (c) 1999 by O"Reilly & Associates. * You may distribute this source code for non-commercial purposes only. * You may study, modify, and use this example for any purpose, as long as * this notice is retained. Note that this example is provided "as is", * WITHOUT WARRANTY of any kind either expressed or implied. */
import java.awt.Color; import java.awt.datatransfer.*; import java.io.*; /**
* This class is used to transfer a Color object via cut-and-paste or * drag-and-drop. It allows a color to be transfered as a Color object, * or as a string. Due to a long-standing bug in Java 1.1 and Java 2, * transferring a color as a string to native Windows applications will * not work. */
public class TransferableColor implements Transferable {
// This DataFlavor object is used when we transfer Color objects directly protected static DataFlavor colorFlavor = new DataFlavor(Color.class, "Java Color Object"); // These are the data flavors we support. protected static DataFlavor[] supportedFlavors = { colorFlavor, // Transfer as a Color object DataFlavor.stringFlavor, // Transfer as a String object DataFlavor.plainTextFlavor, // Transfer as a stream of unicode text }; Color color; // The color we encapsulate and transfer /** Create a new TransferableColor that encapsulates the specified color */ public TransferableColor(Color color) { this.color = color; } /** Return a list of DataFlavors we can support */ public DataFlavor[] getTransferDataFlavors() { return supportedFlavors; } /** Check whether a specified DataFlavor is available */ public boolean isDataFlavorSupported(DataFlavor flavor) { if (flavor.equals(colorFlavor) || flavor.equals(DataFlavor.stringFlavor) || flavor.equals(DataFlavor.plainTextFlavor)) return true; return false; } /** * Transfer the data. Given a specified DataFlavor, return an Object * appropriate for that flavor. Throw UnsupportedFlavorException if we * don"t support the requested flavor. */ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { if (flavor.equals(colorFlavor)) return color; else if (flavor.equals(DataFlavor.stringFlavor)) return color.toString(); else if (flavor.equals(DataFlavor.plainTextFlavor)) return new ByteArrayInputStream(color.toString().getBytes("Unicode")); else throw new UnsupportedFlavorException(flavor); }
}
</source>
TransferHandler subclass wraps another TransferHandler and delegates most of its operations to the wrapped handler
<source lang="java">
/*
* Copyright (c) 2004 David Flanagan. All rights reserved. * This code is from the book Java Examples in a Nutshell, 3nd Edition. * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied. * You may study, use, and modify it for any non-commercial purpose, * including teaching and use in open-source projects. * You may distribute it non-commercially as long as you retain this notice. * For a commercial use license, or to purchase the book, * please visit http://www.davidflanagan.ru/javaexamples3. */
import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.InputEvent; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.util.List; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.TransferHandler; /**
* This TransferHandler subclass wraps another TransferHandler and delegates * most of its operations to the wrapped handler. It adds the ability to to drop * or paste files using the predefined DataFlavor.javaFileListFlavor. When a * file list is pasted or dropped, it assumes the files are text, reads them in * order, concatenates their contents, and then passes the resulting string to * the wrapped handler for insertion. */
public class FileTransferHandler extends TransferHandler {
TransferHandler wrappedHandler; // The handler that we wrap // We use this array to test the wrapped handler static DataFlavor[] stringFlavorArray = new DataFlavor[] { DataFlavor.stringFlavor }; /** Pass an existing TransferHandler to this constructor */ public FileTransferHandler(TransferHandler wrappedHandler) { if (wrappedHandler == null) // Fail immediately on null throw new NullPointerException(); this.wrappedHandler = wrappedHandler; // Remember wrapped handler } /** * This method returns true if the TransferHandler knows how to work with one * of the specified flavors. This implementation first checks the superclass, * then checks for fileListFlavor support */ public boolean canImport(JComponent c, DataFlavor[] flavors) { // If the wrapped handler can import it, we"re done if (wrappedHandler.canImport(c, flavors)) return true; // Otherwise, if the wrapped handler can handle string imports, then // see if we are being offered a list of files that we can convert // to a string. if (wrappedHandler.canImport(c, stringFlavorArray)) { for (int i = 0; i < flavors.length; i++) if (flavors[i].equals(DataFlavor.javaFileListFlavor)) return true; } // Otherwise, we can"t import any of the flavors. return false; } /** * If the wrapped handler can import strings and the specified Transferable * can provide its data as a List of File objects, then we read the files, and * pass their contents as a string to the wrapped handler. Otherwise, we offer * the Transferable to the wrapped handler to handle on its own. */ public boolean importData(JComponent c, Transferable t) { // See if we"re offered a java.util.List of java.io.File objects. // We handle this case first because the Transferable is likely to // also offer the filenames as strings, and we want to import the // file contents, not their names! if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor) && wrappedHandler.canImport(c, stringFlavorArray)) { try { List filelist = (List) t.getTransferData(DataFlavor.javaFileListFlavor); // Loop through the files to determine total size int numfiles = filelist.size(); int numbytes = 0; for (int i = 0; i < numfiles; i++) { File f = (File) filelist.get(i); numbytes += (int) f.length(); } // There will never be more characters than bytes in the files char[] text = new char[numbytes]; // to hold file contents int p = 0; // current position in the text[] array // Loop through the files again, reading their content as text for (int i = 0; i < numfiles; i++) { File f = (File) filelist.get(i); Reader r = new BufferedReader(new FileReader(f)); p += r.read(text, p, (int) f.length()); } // Convert the character array to a string and wrap it // in a pre-defined Transferable class for transferring strings StringSelection selection = new StringSelection(new String(text, 0, p)); // Ask the wrapped handler to import the string return wrappedHandler.importData(c, selection); } // If anything goes wrong, just beep to tell the user catch (UnsupportedFlavorException e) { c.getToolkit().beep(); // audible error return false; // return failure code } catch (IOException e) { c.getToolkit().beep(); // audible error return false; // return failure code } } // Otherwise let the wrapped class handle this transferable itself return wrappedHandler.importData(c, t); } /* * The following methods just delegate to the wrapped TransferHandler */ public void exportAsDrag(JComponent c, InputEvent e, int action) { wrappedHandler.exportAsDrag(c, e, action); } public void exportToClipboard(JComponent c, Clipboard clip, int action) { wrappedHandler.exportToClipboard(c, clip, action); } public int getSourceActions(JComponent c) { return wrappedHandler.getSourceActions(c); } public Icon getVisualRepresentation(Transferable t) { // This method is not currently (Java 1.4) used by Swing return wrappedHandler.getVisualRepresentation(t); } /** * This class demonstrates the FileTransferHandler by installing it on a * JTextArea component and providing a JFileChooser to drag and cut files. */ public static void main(String[] args) { // Here"s the text area. Note how we wrap our TransferHandler // around the default handler returned by getTransferHandler() JTextArea textarea = new JTextArea(); TransferHandler defaultHandler = textarea.getTransferHandler(); textarea.setTransferHandler(new FileTransferHandler(defaultHandler)); // Here"s a JFileChooser, with dragging explicitly enabled. JFileChooser filechooser = new JFileChooser(); filechooser.setDragEnabled(true); // Display them both in a window JFrame f = new JFrame("File Transfer Handler Test"); f.getContentPane().add(new JScrollPane(textarea), "Center"); f.getContentPane().add(filechooser, "South"); f.setSize(400, 600); f.setVisible(true); }
}
</source>
Use drag and drop to reorder a list
<source lang="java">
import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragGestureRecognizer; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import javax.swing.DefaultListModel; import javax.swing.DropMode; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.TransferHandler; public class DragDropList extends JList {
DefaultListModel model; public DragDropList() { super(new DefaultListModel()); model = (DefaultListModel) getModel(); setDragEnabled(true); setDropMode(DropMode.INSERT); setTransferHandler(new MyListDropHandler(this)); new MyDragListener(this); model.addElement("a"); model.addElement("b"); model.addElement("c"); } public static void main(String[] a){ JFrame f = new JFrame(); f.add(new JScrollPane(new DragDropList())); f.setSize(300,300); f.setVisible(true); }
} class MyDragListener implements DragSourceListener, DragGestureListener {
DragDropList list; DragSource ds = new DragSource(); public MyDragListener(DragDropList list) { this.list = list; DragGestureRecognizer dgr = ds.createDefaultDragGestureRecognizer(list, DnDConstants.ACTION_MOVE, this); } public void dragGestureRecognized(DragGestureEvent dge) { StringSelection transferable = new StringSelection(Integer.toString(list.getSelectedIndex())); ds.startDrag(dge, DragSource.DefaultCopyDrop, transferable, this); } public void dragEnter(DragSourceDragEvent dsde) { } public void dragExit(DragSourceEvent dse) { } public void dragOver(DragSourceDragEvent dsde) { } public void dragDropEnd(DragSourceDropEvent dsde) { if (dsde.getDropSuccess()) { System.out.println("Succeeded"); } else { System.out.println("Failed"); } } public void dropActionChanged(DragSourceDragEvent dsde) { }
} class MyListDropHandler extends TransferHandler {
DragDropList list; public MyListDropHandler(DragDropList list) { this.list = list; } public boolean canImport(TransferHandler.TransferSupport support) { if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) { return false; } JList.DropLocation dl = (JList.DropLocation) support.getDropLocation(); if (dl.getIndex() == -1) { return false; } else { return true; } } public boolean importData(TransferHandler.TransferSupport support) { if (!canImport(support)) { return false; } Transferable transferable = support.getTransferable(); String indexString; try { indexString = (String) transferable.getTransferData(DataFlavor.stringFlavor); } catch (Exception e) { return false; } int index = Integer.parseInt(indexString); JList.DropLocation dl = (JList.DropLocation) support.getDropLocation(); int dropTargetIndex = dl.getIndex(); System.out.println(dropTargetIndex + " : "); System.out.println("inserted"); return true; }
}
</source>