Java Tutorial/Swing/Drag Drop — различия между версиями
Admin (обсуждение | вклад) м (1 версия) |
|
(нет различий)
|
Текущая версия на 15:33, 31 мая 2010
Содержание
- 1 14. Basic drag and drop
- 2 14. Built-in drag and drop support: utilize a TransferHandler class
- 3 14. Choose Drop Action
- 4 14. Create a drag source a drop target and a transferable object.
- 5 14. Demonstrates how to add copy and drag support to a Swing component with TransferHandler
- 6 14. Demonstration of the top-level TransferHandler support on JFrame
- 7 14. Detect a drag initiating gesture in your application
- 8 14. DND Drag and drop List
- 9 14. Drag and drop between JList and JTextField
- 10 14. Drag and drop between JTextArea and JTextField
- 11 14. Drag-and-Drop customization: drag the foreground color from the first label and drop it as the background color into the second one
- 12 14. Drag and drop icons: use an icon property.
- 13 14. Drag-and-Drop Support for Images
- 14 14. Dragging and dropping text between a text area, a list, and a table
- 15 14. Dragging Text from a JLabel
- 16 14. DropMode.INSERT
- 17 14. DropMode.ON
- 18 14. DropMode.ON_OR_INSERT
- 19 14. Illustrates cut, copy, paste and drag and drop using three instances of JList
- 20 14. implements DragGestureListener, Transferable
- 21 14. JTable drag and drop
- 22 14. Location sensitive drag and drop
- 23 14. Making a Component Draggable
- 24 14. ScribblePane allows individual PolyLine lines to be selected, cut, copied, pasted, dragged, and dropped
- 25 14. Set tree drag mode to DropMode.INSERT
- 26 14. Set tree drag mode to DropMode.ON
- 27 14. Set tree drag mode to DropMode.ON_OR_INSERT
- 28 14. Set tree DropMode to DropMode.USE_SELECTION
- 29 14. Transfer both Text and Color between JTextField and JTextArea
- 30 14. Various drop actions
14. Basic drag and drop
/*
* Copyright (c) 1995 - 2008 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:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - 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.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
/*
* BasicDnD.java requires no other files.
*/
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
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.DropMode;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
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.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
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 {
private static JFrame frame;
private JTextArea textArea;
private JTextField textField;
private JList list;
private JTable table;
private JTree tree;
private JColorChooser colorChooser;
private 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.setVisibleRowCount(-1);
list.getSelectionModel().setSelectionMode(
ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
list.setTransferHandler(new TransferHandler() {
public boolean canImport(TransferHandler.TransferSupport info) {
// we only import Strings
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
if (dl.getIndex() == -1) {
return false;
}
return true;
}
public boolean importData(TransferHandler.TransferSupport info) {
if (!info.isDrop()) {
return false;
}
// Check for String flavor
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
displayDropLocation("List doesn"t accept a drop of this type.");
return false;
}
JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
DefaultListModel listModel = (DefaultListModel) list.getModel();
int index = dl.getIndex();
boolean insert = dl.isInsert();
// Get the current string under the drop.
String value = (String) listModel.getElementAt(index);
// Get the string that is being dropped.
Transferable t = info.getTransferable();
String data;
try {
data = (String) t.getTransferData(DataFlavor.stringFlavor);
} catch (Exception e) {
return false;
}
// Display a dialog with the drop information.
String dropValue = "\"" + data + "\" dropped ";
if (dl.isInsert()) {
if (dl.getIndex() == 0) {
displayDropLocation(dropValue + "at beginning of list");
} else if (dl.getIndex() >= list.getModel().getSize()) {
displayDropLocation(dropValue + "at end of list");
} else {
String value1 = (String) list.getModel().getElementAt(
dl.getIndex() - 1);
String value2 = (String) list.getModel()
.getElementAt(dl.getIndex());
displayDropLocation(dropValue + "between \"" + value1 + "\" and \""
+ value2 + "\"");
}
} else {
displayDropLocation(dropValue + "on top of " + "\"" + value + "\"");
}
/**
* This is commented out for the basicdemo.html tutorial page. * If you
* add this code snippet back and delete the * "return false;" line, the
* list will accept drops * of type string. // Perform the actual
* import. if (insert) { listModel.add(index, data); } else {
* listModel.set(index, data); } return true;
*/
return false;
}
public int getSourceActions(JComponent c) {
return COPY;
}
protected Transferable createTransferable(JComponent c) {
JList list = (JList) c;
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 new StringSelection(buff.toString());
}
});
list.setDropMode(DropMode.ON_OR_INSERT);
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;
}
private void displayDropLocation(final String string) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JOptionPane.showMessageDialog(null, string);
}
});
}
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() {
// 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() {
// Turn off metal"s use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
14. Built-in drag and drop support: utilize a TransferHandler class
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);
}
}
14. Choose Drop Action
/*
* Copyright (c) 1995 - 2008 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:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - 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.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
public class ChooseDropActionDemo extends JFrame {
DefaultListModel from = new DefaultListModel();
DefaultListModel copy = new DefaultListModel();
DefaultListModel move = new DefaultListModel();
JList dragFrom;
public ChooseDropActionDemo() {
super("ChooseDropActionDemo");
for (int i = 15; i >= 0; i--) {
from.add(0, "Source item " + i);
}
for (int i = 2; i >= 0; i--) {
copy.add(0, "Target item " + i);
move.add(0, "Target item " + i);
}
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
dragFrom = new JList(from);
dragFrom.setTransferHandler(new FromTransferHandler());
dragFrom.setPrototypeCellValue("List Item WWWWWW");
dragFrom.setDragEnabled(true);
dragFrom.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JLabel label = new JLabel("Drag from here:");
label.setAlignmentX(0f);
p.add(label);
JScrollPane sp = new JScrollPane(dragFrom);
sp.setAlignmentX(0f);
p.add(sp);
add(p, BorderLayout.WEST);
JList moveTo = new JList(move);
moveTo.setTransferHandler(new ToTransferHandler(TransferHandler.COPY));
moveTo.setDropMode(DropMode.INSERT);
JList copyTo = new JList(copy);
copyTo.setTransferHandler(new ToTransferHandler(TransferHandler.MOVE));
copyTo.setDropMode(DropMode.INSERT);
p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
label = new JLabel("Drop to COPY to here:");
;
label.setAlignmentX(0f);
p.add(label);
sp = new JScrollPane(moveTo);
sp.setAlignmentX(0f);
p.add(sp);
label = new JLabel("Drop to MOVE to here:");
label.setAlignmentX(0f);
p.add(label);
sp = new JScrollPane(copyTo);
sp.setAlignmentX(0f);
p.add(sp);
p.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
add(p, BorderLayout.CENTER);
((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder(2, 2,
2, 2));
getContentPane().setPreferredSize(new Dimension(320, 315));
}
private static void createAndShowGUI() {
// Create and set up the window.
ChooseDropActionDemo test = new ChooseDropActionDemo();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Display the window.
test.pack();
test.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Turn off metal"s use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
class FromTransferHandler extends TransferHandler {
public int getSourceActions(JComponent comp) {
return COPY_OR_MOVE;
}
private int index = 0;
public Transferable createTransferable(JComponent comp) {
index = dragFrom.getSelectedIndex();
if (index < 0 || index >= from.getSize()) {
return null;
}
return new StringSelection((String) dragFrom.getSelectedValue());
}
public void exportDone(JComponent comp, Transferable trans, int action) {
if (action != MOVE) {
return;
}
from.removeElementAt(index);
}
}
class ToTransferHandler extends TransferHandler {
int action;
public ToTransferHandler(int action) {
this.action = action;
}
public boolean canImport(TransferHandler.TransferSupport support) {
// for the demo, we"ll only support drops (not clipboard paste)
if (!support.isDrop()) {
return false;
}
// we only import Strings
if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
boolean actionSupported = (action & support.getSourceDropActions()) == action;
if (actionSupported) {
support.setDropAction(action);
return true;
}
return false;
}
public boolean importData(TransferHandler.TransferSupport support) {
// if we can"t handle the import, say so
if (!canImport(support)) {
return false;
}
// fetch the drop location
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
int index = dl.getIndex();
// fetch the data and bail if this fails
String data;
try {
data = (String) support.getTransferable().getTransferData(
DataFlavor.stringFlavor);
} catch (UnsupportedFlavorException e) {
return false;
} catch (java.io.IOException e) {
return false;
}
JList list = (JList) support.getComponent();
DefaultListModel model = (DefaultListModel) list.getModel();
model.insertElementAt(data, index);
Rectangle rect = list.getCellBounds(index, index);
list.scrollRectToVisible(rect);
list.setSelectedIndex(index);
list.requestFocusInWindow();
return true;
}
}
}
14. Create a drag source a drop target and a transferable object.
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);
}
}
14. Demonstrates how to add copy and drag support to a Swing component with TransferHandler
/*
* 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.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.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.text.DateFormat;
import java.util.Date;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JLabel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.TransferHandler;
import javax.swing.border.LineBorder;
/**
* A custom Swing component that displays a simple digital clock. Demonstrates
* how to add copy and drag support to a Swing component with TransferHandler.
*/
public class DigitalClock extends JLabel {
DateFormat format; // How to display the time in string form
int updateFrequency; // How often to update the time (in milliseconds)
Timer timer; // Triggers repeated updates to the clock
public DigitalClock() {
// Set default values for our properties
setFormat(DateFormat.getTimeInstance(DateFormat.MEDIUM, getLocale()));
setUpdateFrequency(1000); // Update once a second
// Specify a Swing TransferHandler object to do the dirty work of
// copy-and-paste and drag-and-drop for us. This one will transfer
// the value of the "time" property. Since this property is read-only
// it will allow drags but not drops.
setTransferHandler(new TransferHandler("time"));
// Since JLabel does not normally support drag-and-drop, we need an
// event handler to detect a drag and start the transfer.
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
getTransferHandler().exportAsDrag(DigitalClock.this, e, TransferHandler.COPY);
}
});
// Before we can have a keyboard binding for a Copy command,
// the component needs to be able to accept keyboard focus.
setFocusable(true);
// Request focus when we"re clicked on
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
requestFocus();
}
});
// Use a LineBorder to indicate when we"ve got the keyboard focus
addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
setBorder(LineBorder.createBlackLineBorder());
}
public void focusLost(FocusEvent e) {
setBorder(null);
}
});
// Now bind the Ctrl-C keystroke to a "Copy" command.
InputMap im = new InputMap();
im.setParent(getInputMap(WHEN_FOCUSED));
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK), "Copy");
setInputMap(WHEN_FOCUSED, im);
// And bind the "Copy" command to a pre-defined Action that performs
// a copy using the TransferHandler we"ve installed.
ActionMap am = new ActionMap();
am.setParent(getActionMap());
am.put("Copy", TransferHandler.getCopyAction());
setActionMap(am);
// Create a javax.swing.Timer object that will generate ActionEvents
// to tell us when to update the displayed time. Every updateFrequency
// milliseconds, this timer will cause the actionPerformed() method
// to be invoked. (For non-GUI applications, see java.util.Timer.)
timer = new Timer(updateFrequency, new ActionListener() {
public void actionPerformed(ActionEvent e) {
setText(getTime()); // set label to current time string
}
});
timer.setInitialDelay(0); // Do the first update immediately
timer.start(); // Start timing now!
}
// Return the current time as a String.
// This is the property accessor method used by the TransferHandler.
// Since there is a getter, but no setter, the TransferHandler will
// reject any attempts to drop data on us.
public String getTime() {
// Use the DateFormat object to convert current time to a string
return format.format(new Date());
}
// Here are two related property setter methods
public void setFormat(DateFormat format) {
this.format = format;
}
public void setUpdateFrequency(int ms) {
this.updateFrequency = ms;
}
}
14. Demonstration of the top-level TransferHandler support on JFrame
/*
* Copyright (c) 1995 - 2008 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:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - 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.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.util.*;
/**
* Demonstration of the top-level {@code TransferHandler}
* support on {@code JFrame}.
*
* @author Shannon Hickey
*/
public class TopLevelTransferHandlerDemo extends JFrame {
private static boolean DEMO = false;
private JDesktopPane dp = new JDesktopPane();
private DefaultListModel listModel = new DefaultListModel();
private JList list = new JList(listModel);
private static int left;
private static int top;
private JCheckBoxMenuItem copyItem;
private JCheckBoxMenuItem nullItem;
private JCheckBoxMenuItem thItem;
private class Doc extends InternalFrameAdapter implements ActionListener {
String name;
JInternalFrame frame;
TransferHandler th;
JTextArea area;
public Doc(File file) {
this.name = file.getName();
try {
init(file.toURI().toURL());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
public Doc(String name) {
this.name = name;
init(getClass().getResource(name));
}
private void init(URL url) {
frame = new JInternalFrame(name);
frame.addInternalFrameListener(this);
listModel.add(listModel.size(), this);
area = new JTextArea();
area.setMargin(new Insets(5, 5, 5, 5));
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
String in;
while ((in = reader.readLine()) != null) {
area.append(in);
area.append("\n");
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
return;
}
th = area.getTransferHandler();
area.setFont(new Font("monospaced", Font.PLAIN, 12));
area.setCaretPosition(0);
area.setDragEnabled(true);
area.setDropMode(DropMode.INSERT);
frame.getContentPane().add(new JScrollPane(area));
dp.add(frame);
frame.show();
if (DEMO) {
frame.setSize(300, 200);
} else {
frame.setSize(400, 300);
}
frame.setResizable(true);
frame.setClosable(true);
frame.setIconifiable(true);
frame.setMaximizable(true);
frame.setLocation(left, top);
incr();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
select();
}
});
nullItem.addActionListener(this);
setNullTH();
}
public void internalFrameClosing(InternalFrameEvent event) {
listModel.removeElement(this);
nullItem.removeActionListener(this);
}
public void internalFrameOpened(InternalFrameEvent event) {
int index = listModel.indexOf(this);
list.getSelectionModel().setSelectionInterval(index, index);
}
public void internalFrameActivated(InternalFrameEvent event) {
int index = listModel.indexOf(this);
list.getSelectionModel().setSelectionInterval(index, index);
}
public String toString() {
return name;
}
public void select() {
try {
frame.toFront();
frame.setSelected(true);
} catch (java.beans.PropertyVetoException e) {}
}
public void actionPerformed(ActionEvent ae) {
setNullTH();
}
public void setNullTH() {
if (nullItem.isSelected()) {
area.setTransferHandler(null);
} else {
area.setTransferHandler(th);
}
}
}
private TransferHandler handler = new TransferHandler() {
public boolean canImport(TransferHandler.TransferSupport support) {
if (!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
return false;
}
if (copyItem.isSelected()) {
boolean copySupported = (COPY & support.getSourceDropActions()) == COPY;
if (!copySupported) {
return false;
}
support.setDropAction(COPY);
}
return true;
}
public boolean importData(TransferHandler.TransferSupport support) {
if (!canImport(support)) {
return false;
}
Transferable t = support.getTransferable();
try {
java.util.List<File> l =
(java.util.List<File>)t.getTransferData(DataFlavor.javaFileListFlavor);
for (File f : l) {
new Doc(f);
}
} catch (UnsupportedFlavorException e) {
return false;
} catch (IOException e) {
return false;
}
return true;
}
};
private static void incr() {
left += 30;
top += 30;
if (top == 150) {
top = 0;
}
}
public TopLevelTransferHandlerDemo() {
super("TopLevelTransferHandlerDemo");
setJMenuBar(createDummyMenuBar());
getContentPane().add(createDummyToolBar(), BorderLayout.NORTH);
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, list, dp);
sp.setDividerLocation(120);
getContentPane().add(sp);
//new Doc("sample.txt");
//new Doc("sample.txt");
//new Doc("sample.txt");
list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
return;
}
Doc val = (Doc)list.getSelectedValue();
if (val != null) {
val.select();
}
}
});
final TransferHandler th = list.getTransferHandler();
nullItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (nullItem.isSelected()) {
list.setTransferHandler(null);
} else {
list.setTransferHandler(th);
}
}
});
thItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (thItem.isSelected()) {
setTransferHandler(handler);
} else {
setTransferHandler(null);
}
}
});
dp.setTransferHandler(handler);
}
private static void createAndShowGUI(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
}
TopLevelTransferHandlerDemo test = new TopLevelTransferHandlerDemo();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
if (DEMO) {
test.setSize(493, 307);
} else {
test.setSize(800, 600);
}
test.setLocationRelativeTo(null);
test.setVisible(true);
test.list.requestFocus();
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Turn off metal"s use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI(args);
}
});
}
private JToolBar createDummyToolBar() {
JToolBar tb = new JToolBar();
JButton b;
b = new JButton("New");
b.setRequestFocusEnabled(false);
tb.add(b);
b = new JButton("Open");
b.setRequestFocusEnabled(false);
tb.add(b);
b = new JButton("Save");
b.setRequestFocusEnabled(false);
tb.add(b);
b = new JButton("Print");
b.setRequestFocusEnabled(false);
tb.add(b);
b = new JButton("Preview");
b.setRequestFocusEnabled(false);
tb.add(b);
tb.setFloatable(false);
return tb;
}
private JMenuBar createDummyMenuBar() {
JMenuBar mb = new JMenuBar();
mb.add(createDummyMenu("File"));
mb.add(createDummyMenu("Edit"));
mb.add(createDummyMenu("Search"));
mb.add(createDummyMenu("View"));
mb.add(createDummyMenu("Tools"));
mb.add(createDummyMenu("Help"));
JMenu demo = new JMenu("Demo");
demo.setMnemonic(KeyEvent.VK_D);
mb.add(demo);
thItem = new JCheckBoxMenuItem("Use Top-Level TransferHandler");
thItem.setMnemonic(KeyEvent.VK_T);
demo.add(thItem);
nullItem = new JCheckBoxMenuItem("Remove TransferHandler from List and Text");
nullItem.setMnemonic(KeyEvent.VK_R);
demo.add(nullItem);
copyItem = new JCheckBoxMenuItem("Use COPY Action");
copyItem.setMnemonic(KeyEvent.VK_C);
demo.add(copyItem);
return mb;
}
private JMenu createDummyMenu(String str) {
JMenu menu = new JMenu(str);
JMenuItem item = new JMenuItem("[Empty]");
item.setEnabled(false);
menu.add(item);
return menu;
}
}
14. Detect a drag initiating gesture in your application
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();
}
}
14. DND Drag and drop List
/**
* This is an example of a component, which serves as a DragSource as
* well as Drop Target.
* To illustrate the concept, JList has been used as a droppable target
* and a draggable source.
* Any component can be used instead of a JList.
* The code also contains debugging messages which can be used for
* diagnostics and understanding the flow of events.
*
* @version 1.0
*/
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.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 javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.ListModel;
public class DNDList extends JList implements DropTargetListener, DragSourceListener, DragGestureListener
{
/**
* enables this component to be a dropTarget
*/
DropTarget dropTarget = null;
/**
* enables this component to be a Drag Source
*/
DragSource dragSource = null;
/**
* constructor - initializes the DropTarget and DragSource.
*/
public DNDList( ListModel dataModel )
{
super( dataModel );
dropTarget = new DropTarget( this, this );
dragSource = new DragSource();
dragSource.createDefaultDragGestureRecognizer( this, DnDConstants.ACTION_MOVE, this );
}
/**
* is invoked when you are dragging over the DropSite
*
*/
public void dragEnter( DropTargetDragEvent event )
{
// debug messages for diagnostics
System.out.println( "dragEnter" );
event.acceptDrag( DnDConstants.ACTION_MOVE );
}
/**
* is invoked when you are exit the DropSite without dropping
*
*/
public void dragExit( DropTargetEvent event )
{
System.out.println( "dragExit" );
}
/**
* is invoked when a drag operation is going on
*
*/
public void dragOver( DropTargetDragEvent event )
{
System.out.println( "dragOver" );
}
/**
* a drop has occurred
*
*/
public void drop( DropTargetDropEvent event )
{
try
{
Transferable transferable = event.getTransferable();
// we accept only Strings
if( transferable.isDataFlavorSupported( DataFlavor.stringFlavor ) )
{
event.acceptDrop( DnDConstants.ACTION_MOVE );
String s = ( String )transferable.getTransferData( DataFlavor.stringFlavor );
addElement( s );
event.getDropTargetContext().dropComplete( true );
}
else
{
event.rejectDrop();
}
}
catch( Exception exception )
{
System.err.println( "Exception" + exception.getMessage() );
event.rejectDrop();
}
}
/**
* is invoked if the use modifies the current drop gesture
*
*/
public void dropActionChanged( DropTargetDragEvent event )
{
}
/**
* a drag gesture has been initiated
*
*/
public void dragGestureRecognized( DragGestureEvent event )
{
Object selected = getSelectedValue();
if( selected != null )
{
StringSelection text = new StringSelection( selected.toString() );
// as the name suggests, starts the dragging
dragSource.startDrag( event, DragSource.DefaultMoveDrop, text, this );
}
else
{
System.out.println( "nothing was selected" );
}
}
/**
* this message goes to DragSourceListener, informing it that the dragging
* has ended
*
*/
public void dragDropEnd( DragSourceDropEvent event )
{
if( event.getDropSuccess() )
{
removeElement();
}
}
/**
* this message goes to DragSourceListener, informing it that the dragging
* has entered the DropSite
*
*/
public void dragEnter( DragSourceDragEvent event )
{
System.out.println( " dragEnter" );
}
/**
* this message goes to DragSourceListener, informing it that the dragging
* has exited the DropSite
*
*/
public void dragExit( DragSourceEvent event )
{
System.out.println( "dragExit" );
}
/**
* this message goes to DragSourceListener, informing it that the dragging is
* currently ocurring over the DropSite
*
*/
public void dragOver( DragSourceDragEvent event )
{
System.out.println( "dragExit" );
}
/**
* is invoked when the user changes the dropAction
*
*/
public void dropActionChanged( DragSourceDragEvent event )
{
System.out.println( "dropActionChanged" );
}
/**
* adds elements to itself
*
*/
public void addElement( Object s )
{
( ( DefaultListModel )getModel() ).addElement( s.toString() );
}
/**
* removes an element from itself
*/
public void removeElement()
{
( ( DefaultListModel )getModel() ).removeElement( getSelectedValue() );
}
}
14. Drag and drop between JList and JTextField
import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
public class DnDDemo3 {
public static void main(String[] args) {
JPanel north = new JPanel();
north.add(new JLabel("Drag from here:"));
JTextField field = new JTextField(10);
field.setDragEnabled(true);
north.add(field);
final DefaultListModel listModel = new DefaultListModel();
listModel.addElement("first");
listModel.addElement("second");
final JList list = new JList(listModel);
list.setDragEnabled(true);
list.setTransferHandler(new TransferHandler() {
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 data;
try {
data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
} catch (Exception e) {
return false;
}
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
int index = dl.getIndex();
if (dl.isInsert()) {
listModel.add(index, data);
} else {
listModel.set(index, data);
}
Rectangle r = list.getCellBounds(index, index);
list.scrollRectToVisible(r);
return true;
}
});
JScrollPane center = new JScrollPane();
center.setViewportView(list);
list.setDropMode(DropMode.USE_SELECTION);
JPanel cp = new JPanel();
cp.setLayout(new BorderLayout());
cp.add(north, BorderLayout.NORTH);
cp.add(center, BorderLayout.CENTER);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(cp);
frame.pack();
frame.setVisible(true);
}
}
14. Drag and drop between JTextArea and JTextField
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class DnDBetweenJTextAreaAndJTextFieldDemo {
public static void main(String[] args) {
JFrame frame = new JFrame("Drag and Drop Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new JPanel());
JTextField textField = new JTextField(25);
textField.setText("www.jexp.ru");
frame.add(textField);
JTextArea textArea = new JTextArea(4, 25);
textArea.setText("Demonstrating\ndrag and drop");
frame.getContentPane().add(new JScrollPane(textArea));
textArea.setDragEnabled(true);
textField.setDragEnabled(true);
frame.pack();
frame.setVisible(true);
}
}
14. Drag-and-Drop customization: drag the foreground color from the first label and drop it as the background color into the second one
/*
* 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.Color;
import java.awt.FlowLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.TransferHandler;
/**
* Simple Drag-and-Drop customization: drag the foreground color from the first
* label and drop it as the background color into the second one. Try it also
* using the ShowBean program to display a JColorChooser component with
* dragEnabled=true.
*/
public class ColorDrag {
public static void main(String args[]) {
// Create two JLabel objects
final JLabel label1 = new JLabel("Drag here");
JLabel label2 = new JLabel("Drop here");
// Register TransferHandler objects on them: label1 transfers its
// foreground color and label2 transfers its background color.
label1.setTransferHandler(new TransferHandler("foreground"));
label2.setTransferHandler(new TransferHandler("background"));
// Give label1 a foreground color other than the default
// Make label2 opaque so it displays its background color
label1.setForeground(new Color(100, 100, 200));
label2.setOpaque(true);
// Now look for drag gestures over label1. When one occurs,
// tell the TransferHandler to begin a drag.
// Exercise: modify this gesture recognition so that the drag doesn"t
// begin until the mouse has moved 4 pixels. This helps to keep
// drags distinct from sloppy clicks. To do this, you"ll need both
// a MouseListener and a MouseMotionListener.
label1.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
TransferHandler handler = label1.getTransferHandler();
handler.exportAsDrag(label1, e, TransferHandler.COPY);
}
});
// Create a window, add the labels, and make it all visible.
JFrame f = new JFrame("ColorDrag");
f.getContentPane().setLayout(new FlowLayout());
f.getContentPane().add(label1);
f.getContentPane().add(label2);
f.pack();
f.setVisible(true);
}
}
14. Drag and drop icons: use an icon property.
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);
}
}
14. Drag-and-Drop Support for Images
To transfer something other than a simple property, you need to create an implementation of the Transferable interface,
import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import javax.swing.AbstractButton;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.TransferHandler;
class ImageSelection extends TransferHandler implements Transferable {
private static final DataFlavor flavors[] = { DataFlavor.imageFlavor };
private Image image;
public int getSourceActions(JComponent c) {
return TransferHandler.COPY;
}
public boolean canImport(JComponent comp, DataFlavor flavor[]) {
if (!(comp instanceof JLabel) && !(comp instanceof AbstractButton)) {
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
image = null;
if (comp instanceof JLabel) {
JLabel label = (JLabel) comp;
Icon icon = label.getIcon();
if (icon instanceof ImageIcon) {
image = ((ImageIcon) icon).getImage();
return this;
}
} else if (comp instanceof AbstractButton) {
AbstractButton button = (AbstractButton) comp;
Icon icon = button.getIcon();
if (icon instanceof ImageIcon) {
image = ((ImageIcon) icon).getImage();
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) {
}
}
} else if (comp instanceof AbstractButton) {
AbstractButton button = (AbstractButton) comp;
if (t.isDataFlavorSupported(flavors[0])) {
try {
image = (Image) t.getTransferData(flavors[0]);
ImageIcon icon = new ImageIcon(image);
button.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 flavors[0].equals(flavor);
}
}
public class DragImage {
public static void main(String args[]) {
JFrame frame = new JFrame("Drag Image");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Icon icon = new ImageIcon("yourFile.gif");
JLabel label = new JLabel(icon);
label.setTransferHandler(new ImageSelection());
MouseListener listener = new MouseAdapter() {
public void mousePressed(MouseEvent me) {
JComponent comp = (JComponent) me.getSource();
TransferHandler handler = comp.getTransferHandler();
handler.exportAsDrag(comp, me, TransferHandler.COPY);
}
};
label.addMouseListener(listener);
frame.add(new JScrollPane(label), BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
14. Dragging and dropping text between a text area, a list, and a table
/*
*
* Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
*
* Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
* modify and redistribute this software in source and binary code form,
* provided that i) this copyright notice and license appear on all copies of
* the software; and ii) Licensee does not utilize the software in a manner
* which is disparaging to Sun.
*
* 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 AND ITS LICENSORS SHALL NOT BE
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THE 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 SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* This software is not designed or intended for use in on-line control of
* aircraft, air traffic, aircraft navigation or aircraft communications; or in
* the design, construction, operation or maintenance of any nuclear
* facility. Licensee represents and warrants that it will not use or
* redistribute the Software for such purposes.
*/
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() {
//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();
}
});
}
}
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;
}
}
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;
}
}
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;
}
}
14. Dragging Text from a JLabel
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
public class DragLabel {
public static void main(String args[]) {
JFrame frame = new JFrame("Drag Label");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Hello, World");
label.setTransferHandler(new TransferHandler("foreground"));
MouseListener listener = new MouseAdapter() {
public void mousePressed(MouseEvent me) {
JComponent comp = (JComponent) me.getSource();
TransferHandler handler = comp.getTransferHandler();
handler.exportAsDrag(comp, me, TransferHandler.COPY);
}
};
label.addMouseListener(listener);
frame.add(label, BorderLayout.SOUTH);
JTextField text = new JTextField();
frame.add(text, BorderLayout.NORTH);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
14. DropMode.INSERT
import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
public class DropModeINSERT {
public static void main(String[] args) {
JPanel north = new JPanel();
north.add(new JLabel("Drag from here:"));
JTextField field = new JTextField(10);
field.setDragEnabled(true);
north.add(field);
final DefaultListModel listModel = new DefaultListModel();
listModel.addElement("first");
listModel.addElement("second");
final JList list = new JList(listModel);
list.setDragEnabled(true);
list.setTransferHandler(new TransferHandler() {
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 data;
try {
data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
} catch (Exception e) {
return false;
}
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
int index = dl.getIndex();
if (dl.isInsert()) {
listModel.add(index, data);
} else {
listModel.set(index, data);
}
// Scroll to display the element that was dropped
Rectangle r = list.getCellBounds(index, index);
list.scrollRectToVisible(r);
return true;
}
});
JScrollPane center = new JScrollPane();
center.setViewportView(list);
list.setDropMode(DropMode.INSERT);
JPanel cp = new JPanel();
cp.setLayout(new BorderLayout());
cp.add(north, BorderLayout.NORTH);
cp.add(center, BorderLayout.CENTER);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(cp);
frame.pack();
frame.setVisible(true);
}
}
14. DropMode.ON
import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
public class DropModeON {
public static void main(String[] args) {
JPanel north = new JPanel();
north.add(new JLabel("Drag from here:"));
JTextField field = new JTextField(10);
field.setDragEnabled(true);
north.add(field);
final DefaultListModel listModel = new DefaultListModel();
listModel.addElement("first");
listModel.addElement("second");
final JList list = new JList(listModel);
list.setDragEnabled(true);
list.setTransferHandler(new TransferHandler() {
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 data;
try {
data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
} catch (Exception e) {
return false;
}
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
int index = dl.getIndex();
if (dl.isInsert()) {
listModel.add(index, data);
} else {
listModel.set(index, data);
}
// Scroll to display the element that was dropped
Rectangle r = list.getCellBounds(index, index);
list.scrollRectToVisible(r);
return true;
}
});
JScrollPane center = new JScrollPane();
center.setViewportView(list);
list.setDropMode(DropMode.ON);
JPanel cp = new JPanel();
cp.setLayout(new BorderLayout());
cp.add(north, BorderLayout.NORTH);
cp.add(center, BorderLayout.CENTER);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(cp);
frame.pack();
frame.setVisible(true);
}
}
14. DropMode.ON_OR_INSERT
import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
public class DropModeON_OR_INSERT {
public static void main(String[] args) {
JPanel north = new JPanel();
north.add(new JLabel("Drag from here:"));
JTextField field = new JTextField(10);
field.setDragEnabled(true);
north.add(field);
final DefaultListModel listModel = new DefaultListModel();
listModel.addElement("first");
listModel.addElement("second");
final JList list = new JList(listModel);
list.setDragEnabled(true);
list.setTransferHandler(new TransferHandler() {
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 data;
try {
data = (String) transferable.getTransferData(DataFlavor.stringFlavor);
} catch (Exception e) {
return false;
}
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
int index = dl.getIndex();
if (dl.isInsert()) {
listModel.add(index, data);
} else {
listModel.set(index, data);
}
// Scroll to display the element that was dropped
Rectangle r = list.getCellBounds(index, index);
list.scrollRectToVisible(r);
return true;
}
});
JScrollPane center = new JScrollPane();
center.setViewportView(list);
list.setDropMode(DropMode.ON_OR_INSERT);
JPanel cp = new JPanel();
cp.setLayout(new BorderLayout());
cp.add(north, BorderLayout.NORTH);
cp.add(center, BorderLayout.CENTER);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(cp);
frame.pack();
frame.setVisible(true);
}
}
14. Illustrates cut, copy, paste and drag and drop using three instances of JList
/*
* Copyright (c) 1995 - 2008 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:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - 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.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
/**
* ListCutPaste.java requires the following files:
* ListTransferHandler.java
* TransferActionListener.java
*/
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
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.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
/**
* The ListCutPaste example illustrates cut, copy, paste and drag and drop using
* three instances of JList. The TransferActionListener class listens for one of
* the CCP actions and, when one occurs, forwards the action to the component
* which currently has the focus.
*/
public class ListCutPaste extends JPanel {
ListTransferHandler lh;
public ListCutPaste() {
super(new BorderLayout());
lh = new ListTransferHandler();
JPanel panel = new JPanel(new GridLayout(1, 3));
DefaultListModel list1Model = new DefaultListModel();
list1Model.addElement("alpha");
list1Model.addElement("beta");
list1Model.addElement("gamma");
list1Model.addElement("delta");
list1Model.addElement("epsilon");
list1Model.addElement("zeta");
JList list1 = new JList(list1Model);
list1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane sp1 = new JScrollPane(list1);
sp1.setPreferredSize(new Dimension(400, 100));
list1.setDragEnabled(true);
list1.setTransferHandler(lh);
list1.setDropMode(DropMode.ON_OR_INSERT);
setMappings(list1);
JPanel pan1 = new JPanel(new BorderLayout());
pan1.add(sp1, BorderLayout.CENTER);
pan1.setBorder(BorderFactory.createTitledBorder("Greek Alphabet"));
panel.add(pan1);
DefaultListModel list2Model = new DefaultListModel();
list2Model.addElement("uma");
list2Model.addElement("dois");
list2Model.addElement("tres");
list2Model.addElement("quatro");
list2Model.addElement("cinco");
list2Model.addElement("seis");
JList list2 = new JList(list2Model);
list2.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list2.setDragEnabled(true);
JScrollPane sp2 = new JScrollPane(list2);
sp2.setPreferredSize(new Dimension(400, 100));
list2.setTransferHandler(lh);
list2.setDropMode(DropMode.INSERT);
setMappings(list2);
JPanel pan2 = new JPanel(new BorderLayout());
pan2.add(sp2, BorderLayout.CENTER);
pan2.setBorder(BorderFactory.createTitledBorder("Portuguese Numbers"));
panel.add(pan2);
DefaultListModel list3Model = new DefaultListModel();
list3Model.addElement("adeen");
list3Model.addElement("dva");
list3Model.addElement("tri");
list3Model.addElement("chyetirye");
list3Model.addElement("pyat");
list3Model.addElement("shest");
JList list3 = new JList(list3Model);
list3.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list3.setDragEnabled(true);
JScrollPane sp3 = new JScrollPane(list3);
sp3.setPreferredSize(new Dimension(400, 100));
list3.setTransferHandler(lh);
list3.setDropMode(DropMode.ON);
setMappings(list3);
JPanel pan3 = new JPanel(new BorderLayout());
pan3.add(sp3, BorderLayout.CENTER);
pan3.setBorder(BorderFactory.createTitledBorder("Russian Numbers"));
panel.add(pan3);
setPreferredSize(new Dimension(500, 200));
add(panel, 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);
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;
}
/**
* Add the cut/copy/paste actions to the action map.
*/
private void setMappings(JList list) {
ActionMap map = list.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());
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("ListCutPaste");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create and set up the menu bar and content pane.
ListCutPaste demo = new ListCutPaste();
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() {
// Turn off metal"s use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}/*
* Copyright (c) 1995 - 2008 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:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
/*
* ListTransferHandler.java is used by the ListCutPaste example.
*/
class ListTransferHandler extends TransferHandler {
/**
* Perform the actual data import.
*/
public boolean importData(TransferHandler.TransferSupport info) {
String data = null;
// If we can"t handle the import, bail now.
if (!canImport(info)) {
return false;
}
JList list = (JList) info.getComponent();
DefaultListModel model = (DefaultListModel) list.getModel();
// Fetch the data -- bail if this fails
try {
data = (String) info.getTransferable().getTransferData(
DataFlavor.stringFlavor);
} catch (UnsupportedFlavorException ufe) {
System.out.println("importData: unsupported data flavor");
return false;
} catch (IOException ioe) {
System.out.println("importData: I/O exception");
return false;
}
if (info.isDrop()) { // This is a drop
JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
int index = dl.getIndex();
if (dl.isInsert()) {
model.add(index, data);
return true;
} else {
model.set(index, data);
return true;
}
} else { // This is a paste
int index = list.getSelectedIndex();
// if there is a valid selection,
// insert data after the selection
if (index >= 0) {
model.add(list.getSelectedIndex() + 1, data);
// else append to the end of the list
} else {
model.addElement(data);
}
return true;
}
}
/**
* Bundle up the data for export.
*/
protected Transferable createTransferable(JComponent c) {
JList list = (JList) c;
int index = list.getSelectedIndex();
String value = (String) list.getSelectedValue();
return new StringSelection(value);
}
/**
* The list handles both copy and move actions.
*/
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
/**
* When the export is complete, remove the old list entry if the action was a
* move.
*/
protected void exportDone(JComponent c, Transferable data, int action) {
if (action != MOVE) {
return;
}
JList list = (JList) c;
DefaultListModel model = (DefaultListModel) list.getModel();
int index = list.getSelectedIndex();
model.remove(index);
}
/**
* We only support importing strings.
*/
public boolean canImport(TransferHandler.TransferSupport support) {
// we only import Strings
if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
return true;
}
}
/*
* Copyright (c) 1995 - 2008 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:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
/*
* TransferActionListener.java is used by the ListCutPaste 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));
}
}
}
14. implements DragGestureListener, Transferable
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();
}
}
14. JTable drag and drop
/*
* Copyright (c) 1995 - 2008 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:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - 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.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
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.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
public class FillViewportHeightDemo extends JFrame implements ActionListener {
private DefaultListModel model = new DefaultListModel();
private int count = 0;
private JTable table;
private JCheckBoxMenuItem fillBox;
private DefaultTableModel tableModel;
private static String getNextString(int count) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < 5; i++) {
buf.append(String.valueOf(count));
buf.append(",");
}
// remove last newline
buf.deleteCharAt(buf.length() - 1);
return buf.toString();
}
private static DefaultTableModel getDefaultTableModel() {
String[] cols = { "Foo", "Toto", "Kala", "Pippo", "Boing" };
return new DefaultTableModel(null, cols);
}
public FillViewportHeightDemo() {
super("Empty Table DnD Demo");
tableModel = getDefaultTableModel();
table = new JTable(tableModel);
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.setDropMode(DropMode.INSERT_ROWS);
table.setTransferHandler(new TransferHandler() {
public boolean canImport(TransferSupport support) {
// for the demo, we"ll only support drops (not clipboard paste)
if (!support.isDrop()) {
return false;
}
// we only import Strings
if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
return true;
}
public boolean importData(TransferSupport support) {
// if we can"t handle the import, say so
if (!canImport(support)) {
return false;
}
// fetch the drop location
JTable.DropLocation dl = (JTable.DropLocation) support
.getDropLocation();
int row = dl.getRow();
// fetch the data and bail if this fails
String data;
try {
data = (String) support.getTransferable().getTransferData(
DataFlavor.stringFlavor);
} catch (UnsupportedFlavorException e) {
return false;
} catch (IOException e) {
return false;
}
String[] rowData = data.split(",");
tableModel.insertRow(row, rowData);
Rectangle rect = table.getCellRect(row, 0, false);
if (rect != null) {
table.scrollRectToVisible(rect);
}
// demo stuff - remove for blog
model.removeAllElements();
model.insertElementAt(getNextString(count++), 0);
// end demo stuff
return true;
}
});
JList dragFrom = new JList(model);
dragFrom.setFocusable(false);
dragFrom.setPrototypeCellValue(getNextString(100));
model.insertElementAt(getNextString(count++), 0);
dragFrom.setDragEnabled(true);
dragFrom.setBorder(BorderFactory.createLoweredBevelBorder());
dragFrom.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent me) {
if (SwingUtilities.isLeftMouseButton(me) && me.getClickCount() % 2 == 0) {
String text = (String) model.getElementAt(0);
String[] rowData = text.split(",");
tableModel.insertRow(table.getRowCount(), rowData);
model.removeAllElements();
model.insertElementAt(getNextString(count++), 0);
}
}
});
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
JPanel wrap = new JPanel();
wrap.add(new JLabel("Drag from here:"));
wrap.add(dragFrom);
p.add(Box.createHorizontalStrut(4));
p.add(Box.createGlue());
p.add(wrap);
p.add(Box.createGlue());
p.add(Box.createHorizontalStrut(4));
getContentPane().add(p, BorderLayout.NORTH);
JScrollPane sp = new JScrollPane(table);
getContentPane().add(sp, BorderLayout.CENTER);
fillBox = new JCheckBoxMenuItem("Fill Viewport Height");
fillBox.addActionListener(this);
JMenuBar mb = new JMenuBar();
JMenu options = new JMenu("Options");
mb.add(options);
setJMenuBar(mb);
JMenuItem clear = new JMenuItem("Reset");
clear.addActionListener(this);
options.add(clear);
options.add(fillBox);
getContentPane().setPreferredSize(new Dimension(260, 180));
}
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == fillBox) {
table.setFillsViewportHeight(fillBox.isSelected());
} else {
tableModel.setRowCount(0);
count = 0;
model.removeAllElements();
model.insertElementAt(getNextString(count++), 0);
}
}
private static void createAndShowGUI() {
// Create and set up the window.
FillViewportHeightDemo test = new FillViewportHeightDemo();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Display the window.
test.pack();
test.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Turn off metal"s use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
14. Location sensitive drag and drop
/*
* Copyright (c) 1995 - 2008 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:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - 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.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
public class LocationSensitiveDemo extends JFrame {
private DefaultListModel model = new DefaultListModel();
private int count = 0;
private JTree tree;
private JComboBox indicateCombo;
private DefaultTreeModel treeModel;
private TreePath namesPath;
private static DefaultTreeModel getDefaultTreeModel() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("things");
DefaultMutableTreeNode parent;
DefaultMutableTreeNode nparent;
parent = new DefaultMutableTreeNode("colors");
root.add(parent);
parent.add(new DefaultMutableTreeNode("red"));
parent.add(new DefaultMutableTreeNode("yellow"));
parent.add(new DefaultMutableTreeNode("green"));
parent.add(new DefaultMutableTreeNode("blue"));
parent.add(new DefaultMutableTreeNode("purple"));
parent = new DefaultMutableTreeNode("names");
root.add(parent);
nparent = new DefaultMutableTreeNode("men");
nparent.add(new DefaultMutableTreeNode("jack"));
nparent.add(new DefaultMutableTreeNode("kieran"));
nparent.add(new DefaultMutableTreeNode("william"));
nparent.add(new DefaultMutableTreeNode("jose"));
parent.add(nparent);
nparent = new DefaultMutableTreeNode("women");
nparent.add(new DefaultMutableTreeNode("jennifer"));
nparent.add(new DefaultMutableTreeNode("holly"));
nparent.add(new DefaultMutableTreeNode("danielle"));
nparent.add(new DefaultMutableTreeNode("tara"));
parent.add(nparent);
parent = new DefaultMutableTreeNode("sports");
root.add(parent);
parent.add(new DefaultMutableTreeNode("basketball"));
parent.add(new DefaultMutableTreeNode("soccer"));
parent.add(new DefaultMutableTreeNode("football"));
nparent = new DefaultMutableTreeNode("hockey");
parent.add(nparent);
nparent.add(new DefaultMutableTreeNode("ice hockey"));
nparent.add(new DefaultMutableTreeNode("roller hockey"));
nparent.add(new DefaultMutableTreeNode("floor hockey"));
nparent.add(new DefaultMutableTreeNode("road hockey"));
parent = new DefaultMutableTreeNode("food");
root.add(parent);
parent.add(new DefaultMutableTreeNode("pizza"));
parent.add(new DefaultMutableTreeNode("wings"));
parent.add(new DefaultMutableTreeNode("pasta"));
nparent = new DefaultMutableTreeNode("fruit");
parent.add(nparent);
nparent.add(new DefaultMutableTreeNode("bananas"));
nparent.add(new DefaultMutableTreeNode("apples"));
nparent.add(new DefaultMutableTreeNode("grapes"));
nparent.add(new DefaultMutableTreeNode("pears"));
return new DefaultTreeModel(root);
}
public LocationSensitiveDemo() {
super("Location Sensitive Drag and Drop Demo");
treeModel = getDefaultTreeModel();
tree = new JTree(treeModel);
tree.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 4));
tree.getSelectionModel().setSelectionMode(
TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
tree.setDropMode(DropMode.ON);
namesPath = tree.getPathForRow(2);
tree.expandRow(2);
tree.expandRow(1);
tree.setRowHeight(0);
tree.setTransferHandler(new TransferHandler() {
public boolean canImport(TransferHandler.TransferSupport info) {
// for the demo, we"ll only support drops (not clipboard paste)
if (!info.isDrop()) {
return false;
}
String item = (String) indicateCombo.getSelectedItem();
if (item.equals("Always")) {
info.setShowDropLocation(true);
} else if (item.equals("Never")) {
info.setShowDropLocation(false);
}
// we only import Strings
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
// fetch the drop location
JTree.DropLocation dl = (JTree.DropLocation) info.getDropLocation();
TreePath path = dl.getPath();
// we don"t support invalid paths or descendants of the names folder
if (path == null || namesPath.isDescendant(path)) {
return false;
}
return true;
}
public boolean importData(TransferHandler.TransferSupport info) {
// if we can"t handle the import, say so
if (!canImport(info)) {
return false;
}
// fetch the drop location
JTree.DropLocation dl = (JTree.DropLocation) info.getDropLocation();
// fetch the path and child index from the drop location
TreePath path = dl.getPath();
int childIndex = dl.getChildIndex();
// fetch the data and bail if this fails
String data;
try {
data = (String) info.getTransferable().getTransferData(
DataFlavor.stringFlavor);
} catch (UnsupportedFlavorException e) {
return false;
} catch (IOException e) {
return false;
}
// if child index is -1, the drop was on top of the path, so we"ll
// treat it as inserting at the end of that path"s list of children
if (childIndex == -1) {
childIndex = tree.getModel().getChildCount(
path.getLastPathComponent());
}
// create a new node to represent the data and insert it into the model
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(data);
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path
.getLastPathComponent();
treeModel.insertNodeInto(newNode, parentNode, childIndex);
// make the new node visible and scroll so that it"s visible
tree.makeVisible(path.pathByAddingChild(newNode));
tree.scrollRectToVisible(tree.getPathBounds(path
.pathByAddingChild(newNode)));
// demo stuff - remove for blog
model.removeAllElements();
model.insertElementAt("String " + (++count), 0);
// end demo stuff
return true;
}
});
JList dragFrom = new JList(model);
dragFrom.setFocusable(false);
dragFrom.setPrototypeCellValue("String 0123456789");
model.insertElementAt("String " + count, 0);
dragFrom.setDragEnabled(true);
dragFrom.setBorder(BorderFactory.createLoweredBevelBorder());
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
JPanel wrap = new JPanel();
wrap.add(new JLabel("Drag from here:"));
wrap.add(dragFrom);
p.add(Box.createHorizontalStrut(4));
p.add(Box.createGlue());
p.add(wrap);
p.add(Box.createGlue());
p.add(Box.createHorizontalStrut(4));
getContentPane().add(p, BorderLayout.NORTH);
getContentPane().add(new JScrollPane(tree), BorderLayout.CENTER);
indicateCombo = new JComboBox(new String[] { "Default", "Always", "Never" });
indicateCombo.setSelectedItem("INSERT");
p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
wrap = new JPanel();
wrap.add(new JLabel("Show drop location:"));
wrap.add(indicateCombo);
p.add(Box.createHorizontalStrut(4));
p.add(Box.createGlue());
p.add(wrap);
p.add(Box.createGlue());
p.add(Box.createHorizontalStrut(4));
getContentPane().add(p, BorderLayout.SOUTH);
getContentPane().setPreferredSize(new Dimension(400, 450));
}
private static void increaseFont(String type) {
Font font = UIManager.getFont(type);
font = font.deriveFont(font.getSize() + 4f);
UIManager.put(type, font);
}
private static void createAndShowGUI() {
// Create and set up the window.
LocationSensitiveDemo test = new LocationSensitiveDemo();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Display the window.
test.pack();
test.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
UIManager
.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
increaseFont("Tree.font");
increaseFont("Label.font");
increaseFont("ComboBox.font");
increaseFont("List.font");
} catch (Exception e) {
}
// Turn off metal"s use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
14. Making a Component Draggable
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");
}
}
14. ScribblePane allows individual PolyLine lines to be selected, cut, copied, pasted, dragged, and dropped
/*
* 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.AWTEvent;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
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.Stroke;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
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.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Externalizable;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
/**
* This rewrite of ScribblePane allows individual PolyLine lines to be selected,
* cut, copied, pasted, dragged, and dropped.
*/
public class TransferableScribblePane extends JComponent {
List lines; // The PolyLines that comprise this scribble
PolyLine currentLine; // The line currently being drawn
PolyLine selectedLine; // The line that is current selected
boolean canDragImage; // Can we drag an image of the line?
// Lines are 3 pixels wide, and the selected line is drawn dashed
static Stroke stroke = new BasicStroke(3.0f);
static Stroke selectedStroke = new BasicStroke(3, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND,
0f, new float[] { 3f, 3f, }, 0f);
// Different borders indicate receptivity to drops
static Border normalBorder = new LineBorder(Color.black, 3);
static Border canDropBorder = new BevelBorder(BevelBorder.LOWERED);
public static void main(String args[]) {
JFrame f = new JFrame("ColorDrag");
f.getContentPane().setLayout(new FlowLayout());
f.getContentPane().add(new TransferableScribblePane());
f.getContentPane().add(new TransferableScribblePane());
f.pack();
f.setVisible(true);
}
// The constructor method
public TransferableScribblePane() {
setPreferredSize(new Dimension(450, 200)); // We need a default size
setBorder(normalBorder); // and a border.
lines = new ArrayList(); // Start with an empty list of lines
// Register interest in mouse button and mouse motion events.
enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
// Enable drag-and-drop by specifying a listener that will be
// notified when a drag begins. dragGestureListener is defined later.
DragSource dragSource = DragSource.getDefaultDragSource();
dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE,
dragGestureListener);
// Enable drops on this component by registering a listener to
// be notified when something is dragged or dropped over us.
this.setDropTarget(new DropTarget(this, dropTargetListener));
// Check whether the system allows us to drag an image of the line
canDragImage = dragSource.isDragImageSupported();
}
/** We override this method to draw ourselves. */
public void paintComponent(Graphics g) {
// Let the superclass do its painting first
super.paintComponent(g);
// Make a copy of the Graphics context so we can modify it
Graphics2D g2 = (Graphics2D) (g.create());
// Our superclass doesn"t paint the background, so do this ourselves.
g2.setColor(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
// Set the line width and color to use for the foreground
g2.setStroke(stroke);
g2.setColor(this.getForeground());
// Now loop through the PolyLine shapes and draw them all
int numlines = lines.size();
for (int i = 0; i < numlines; i++) {
PolyLine line = (PolyLine) lines.get(i);
if (line == selectedLine) { // If it is the selected line
g2.setStroke(selectedStroke); // Set dash pattern
g2.draw(line); // Draw the line
g2.setStroke(stroke); // Revert to solid lines
} else
g2.draw(line); // Otherwise just draw the line
}
}
/**
* This method is called on mouse button events. It begins a new line or tries
* to select an existing line.
*/
public void processMouseEvent(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) { // Left mouse button
if (e.getID() == MouseEvent.MOUSE_PRESSED) { // Pressed down
if (e.isShiftDown()) { // with Shift key
// If the shift key is down, try to select a line
int x = e.getX();
int y = e.getY();
// Loop through the lines checking to see if we hit one
PolyLine selection = null;
int numlines = lines.size();
for (int i = 0; i < numlines; i++) {
PolyLine line = (PolyLine) lines.get(i);
if (line.intersects(x - 2, y - 2, 4, 4)) {
selection = line;
e.consume();
break;
}
}
// If we found an intersecting line, save it and repaint
if (selection != selectedLine) { // If selection changed
selectedLine = selection; // remember which is selected
repaint(); // will make selection dashed
}
} else if (!e.isControlDown()) { // no shift key or ctrl key
// Start a new line on mouse down without shift or ctrl
currentLine = new PolyLine(e.getX(), e.getY());
lines.add(currentLine);
e.consume();
}
} else if (e.getID() == MouseEvent.MOUSE_RELEASED) {// Left Button Up
// End the line on mouse up
if (currentLine != null) {
currentLine = null;
e.consume();
}
}
}
// The superclass method dispatches to registered event listeners
super.processMouseEvent(e);
}
/**
* This method is called for mouse motion events. We don"t have to detect
* gestures that initiate a drag in this method. That is the job of the
* DragGestureRecognizer we created in the constructor: it will notify the
* DragGestureListener defined below.
*/
public void processMouseMotionEvent(MouseEvent e) {
if (e.getID() == MouseEvent.MOUSE_DRAGGED && // If we"re dragging
currentLine != null) { // and a line exists
currentLine.addSegment(e.getX(), e.getY()); // Add a line segment
e.consume(); // Eat the event
repaint(); // Redisplay all lines
}
super.processMouseMotionEvent(e); // Invoke any listeners
}
/** Copy the selected line to the clipboard, then delete it */
public void cut() {
if (selectedLine == null)
return; // Only works if a line is selected
copy(); // Do a Copy operation...
lines.remove(selectedLine); // and then erase the selected line
selectedLine = null;
repaint(); // Repaint because a line was removed
}
/** Copy the selected line to the clipboard */
public void copy() {
if (selectedLine == null)
return; // Only works if a line is selected
// Get the system Clipboard object.
Clipboard c = this.getToolkit().getSystemClipboard();
// Wrap the selected line in a TransferablePolyLine object
// and pass it to the clipboard, with an object to receive notification
// when some other application takes ownership of the clipboard
c.setContents(new TransferablePolyLine((PolyLine) selectedLine.clone()), new ClipboardOwner() {
public void lostOwnership(Clipboard c, Transferable t) {
// This method is called when something else
// is copied to the clipboard. We could use it
// to deselect the selected line, if we wanted.
}
});
}
/** Get a PolyLine from the clipboard, if one exists, and display it */
public void paste() {
// Get the system Clipboard and ask for its Transferable contents
Clipboard c = this.getToolkit().getSystemClipboard();
Transferable t = c.getContents(this);
// See if we can extract a PolyLine from the Transferable object
PolyLine line;
try {
line = (PolyLine) t.getTransferData(TransferablePolyLine.FLAVOR);
} catch (Exception e) { // UnsupportedFlavorException or IOException
// If we get here, the clipboard doesn"t hold a PolyLine we can use
getToolkit().beep(); // So beep to indicate the error
return;
}
lines.add(line); // We got a line from the clipboard, so add it to list
repaint(); // And repaint to make the line appear
}
/** Erase all lines and repaint. */
public void clear() {
lines.clear();
repaint();
}
/**
* This DragGestureListener is notified when the user initiates a drag. We
* passed it to the DragGestureRecognizer we created in the constructor.
*/
public DragGestureListener dragGestureListener = new DragGestureListener() {
public void dragGestureRecognized(DragGestureEvent e) {
// Don"t start a drag if there isn"t a selected line
if (selectedLine == null)
return;
// Find out where the drag began
MouseEvent trigger = (MouseEvent) e.getTriggerEvent();
int x = trigger.getX();
int y = trigger.getY();
// Don"t do anything if the drag was not near the selected line
if (!selectedLine.intersects(x - 4, y - 4, 8, 8))
return;
// Make a copy of the selected line, adjust the copy so that
// the point under the mouse is (0,0), and wrap the copy in a
// Tranferable wrapper.
PolyLine copy = (PolyLine) selectedLine.clone();
copy.translate(-x, -y);
Transferable t = new TransferablePolyLine(copy);
// If the system allows custom images to be dragged, make
// an image of the line on a transparent background
Image dragImage = null;
Point hotspot = null;
if (canDragImage) {
Rectangle box = copy.getBounds();
dragImage = createImage(box.width, box.height);
Graphics2D g = (Graphics2D) dragImage.getGraphics();
g.setColor(new Color(0, 0, 0, 0)); // transparent bg
g.fillRect(0, 0, box.width, box.height);
g.setColor(getForeground());
g.setStroke(selectedStroke);
g.translate(-box.x, -box.y);
g.draw(copy);
hotspot = new Point(-box.x, -box.y);
}
// Now begin dragging the line, specifying the listener
// object to receive notifications about the progress of
// the operation. Note: the startDrag() method is defined by
// the event object, which is unusual.
e.startDrag(null, // Use default drag-and-drop cursors
dragImage, // Use the image, if supported
hotspot, // Ditto for the image hotspot
t, // Drag this object
dragSourceListener); // Send notifications here
}
};
/**
* If this component is the source of a drag, then this DragSourceListener
* will receive notifications about the progress of the drag. The only one we
* use here is dragDropEnd() which is called after a drop occurs. We could use
* the other methods to change cursors or perform other "drag over effects"
*/
public DragSourceListener dragSourceListener = new DragSourceListener() {
// Invoked when dragging stops
public void dragDropEnd(DragSourceDropEvent e) {
if (!e.getDropSuccess())
return; // Ignore failed drops
// If the drop was a move, then delete the selected line
if (e.getDropAction() == DnDConstants.ACTION_MOVE) {
lines.remove(selectedLine);
selectedLine = null;
repaint();
}
}
// The following methods are unused here. We could implement them
// to change custom cursors or perform other "drag over effects".
public void dragEnter(DragSourceDragEvent e) {
}
public void dragExit(DragSourceEvent e) {
}
public void dragOver(DragSourceDragEvent e) {
}
public void dropActionChanged(DragSourceDragEvent e) {
}
};
/**
* This DropTargetListener is notified when something is dragged over this
* component.
*/
public DropTargetListener dropTargetListener = new DropTargetListener() {
// This method is called when something is dragged over us.
// If we understand what is being dragged, then tell the system
// we can accept it, and change our border to provide extra
// "drag under" visual feedback to the user to indicate our
// receptivity to a drop.
public void dragEnter(DropTargetDragEvent e) {
if (e.isDataFlavorSupported(TransferablePolyLine.FLAVOR)) {
e.acceptDrag(e.getDropAction());
setBorder(canDropBorder);
}
}
// Revert to our normal border if the drag moves off us.
public void dragExit(DropTargetEvent e) {
setBorder(normalBorder);
}
// This method is called when something is dropped on us.
public void drop(DropTargetDropEvent e) {
// If a PolyLine is dropped, accept either a COPY or a MOVE
if (e.isDataFlavorSupported(TransferablePolyLine.FLAVOR))
e.acceptDrop(e.getDropAction());
else { // Otherwise, reject the drop and return
e.rejectDrop();
return;
}
// Get the dropped object and extract a PolyLine from it
Transferable t = e.getTransferable();
PolyLine line;
try {
line = (PolyLine) t.getTransferData(TransferablePolyLine.FLAVOR);
} catch (Exception ex) { // UnsupportedFlavor or IOException
getToolkit().beep(); // Something went wrong, so beep
e.dropComplete(false); // Tell the system we failed
return;
}
// Figure out where the drop occurred, and translate so the
// point that was formerly (0,0) is now at that point.
Point p = e.getLocation();
line.translate((float) p.getX(), (float) p.getY());
// Add the line to our list, and repaint
lines.add(line);
repaint();
// Tell the system that we successfully completed the transfer.
// This means it is safe for the initiating component to delete
// its copy of the line
e.dropComplete(true);
}
// We could provide additional drag under effects with this method.
public void dragOver(DropTargetDragEvent e) {
}
// If we used custom cursors, we would update them here.
public void dropActionChanged(DropTargetDragEvent e) {
}
};
}
/**
* This Shape implementation represents a series of connected line segments. It
* is like a Polygon, but is not closed. This class is used by the ScribblePane
* class of the GUI chapter. It implements the Cloneable and Externalizable
* interfaces so it can be used in the Drag-and-Drop examples in the Data
* Transfer chapter.
*/
class PolyLine implements Shape, Cloneable, Externalizable {
float x0, y0; // The starting point of the polyline.
float[] coords; // The x and y coordinates of the end point of each line
// segment packed into a single array for simplicity:
// [x1,y1,x2,y2,...] Note that these are relative to x0,y0
int numsegs; // How many line segments in this PolyLine
// Coordinates of our bounding box, relative to (x0, y0);
float xmin = 0f, xmax = 0f, ymin = 0f, ymax = 0f;
// No arg constructor assumes an origin of (0,0)
// A no-arg constructor is required for the Externalizable interface
public PolyLine() {
this(0f, 0f);
}
// The constructor.
public PolyLine(float x0, float y0) {
setOrigin(x0, y0); // Record the starting point.
numsegs = 0; // Note that we have no line segments, so far
}
/** Set the origin of the PolyLine. Useful when moving it */
public void setOrigin(float x0, float y0) {
this.x0 = x0;
this.y0 = y0;
}
/** Add dx and dy to the origin */
public void translate(float dx, float dy) {
this.x0 += dx;
this.y0 += dy;
}
/**
* Add a line segment to the PolyLine. Note that x and y are absolute
* coordinates, even though the implementation stores them relative to x0, y0;
*/
public void addSegment(float x, float y) {
// Allocate or reallocate the coords[] array when necessary
if (coords == null)
coords = new float[32];
if (numsegs * 2 >= coords.length) {
float[] newcoords = new float[coords.length * 2];
System.arraycopy(coords, 0, newcoords, 0, coords.length);
coords = newcoords;
}
// Convert from absolute to relative coordinates
x = x - x0;
y = y - y0;
// Store the data
coords[numsegs * 2] = x;
coords[numsegs * 2 + 1] = y;
numsegs++;
// Enlarge the bounding box, if necessary
if (x > xmax)
xmax = x;
else if (x < xmin)
xmin = x;
if (y > ymax)
ymax = y;
else if (y < ymin)
ymin = y;
}
/*------------------ The Shape Interface --------------------- */
// Return floating-point bounding box
public Rectangle2D getBounds2D() {
return new Rectangle2D.Float(x0 + xmin, y0 + ymin, xmax - xmin, ymax - ymin);
}
// Return integer bounding box, rounded to outermost pixels.
public Rectangle getBounds() {
return new Rectangle((int) (x0 + xmin - 0.5f), // x0
(int) (y0 + ymin - 0.5f), // y0
(int) (xmax - xmin + 0.5f), // width
(int) (ymax - ymin + 0.5f)); // height
}
// PolyLine shapes are open curves, with no interior.
// The Shape interface says that open curves should be implicitly closed
// for the purposes of insideness testing. For our purposes, however,
// we define PolyLine shapes to have no interior, and the contains()
// methods always return false.
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;
}
// The intersects methods simply test whether any of the line segments
// within a polyline intersects the given rectangle. Strictly speaking,
// the Shape interface requires us to also check whether the rectangle
// is entirely contained within the shape as well. But the contains()
// methods for this class alwasy return false.
// We might improve the efficiency of this method by first checking for
// intersection with the overall bounding box to rule out cases that
// aren"t even close.
public boolean intersects(Rectangle2D r) {
if (numsegs < 1)
return false;
float lastx = x0, lasty = y0;
for (int i = 0; i < numsegs; i++) { // loop through the segments
float x = coords[i * 2] + x0;
float y = coords[i * 2 + 1] + y0;
// See if this line segment intersects the rectangle
if (r.intersectsLine(x, y, lastx, lasty))
return true;
// Otherwise move on to the next segment
lastx = x;
lasty = y;
}
return false; // No line segment intersected the rectangle
}
// This variant method is just defined in terms of the last.
public boolean intersects(double x, double y, double w, double h) {
return intersects(new Rectangle2D.Double(x, y, w, h));
}
// This is the key to the Shape interface; it tells Java2D how to draw
// the shape as a series of lines and curves. We use only lines
public PathIterator getPathIterator(final AffineTransform transform) {
return new PathIterator() {
int curseg = -1; // current segment
// Copy the current segment for thread-safety, so we don"t
// mess up of a segment is added while we"re iterating
int numsegs = PolyLine.this.numsegs;
public boolean isDone() {
return curseg >= numsegs;
}
public void next() {
curseg++;
}
// Get coordinates and type of current segment as floats
public int currentSegment(float[] data) {
int segtype;
if (curseg == -1) { // First time we"re called
data[0] = x0; // Data is the origin point
data[1] = y0;
segtype = SEG_MOVETO; // Returned as a moveto segment
} else { // Otherwise, the data is a segment endpoint
data[0] = x0 + coords[curseg * 2];
data[1] = y0 + coords[curseg * 2 + 1];
segtype = SEG_LINETO; // Returned as a lineto segment
}
// If a tranform was specified, transform point in place
if (transform != null)
transform.transform(data, 0, data, 0, 1);
return segtype;
}
// Same as last method, but use doubles
public int currentSegment(double[] data) {
int segtype;
if (curseg == -1) {
data[0] = x0;
data[1] = y0;
segtype = SEG_MOVETO;
} else {
data[0] = x0 + coords[curseg * 2];
data[1] = y0 + coords[curseg * 2 + 1];
segtype = SEG_LINETO;
}
if (transform != null)
transform.transform(data, 0, data, 0, 1);
return segtype;
}
// This only matters for closed shapes
public int getWindingRule() {
return WIND_NON_ZERO;
}
};
}
// PolyLines never contain curves, so we can ignore the flatness limit
// and implement this method in terms of the one above.
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return getPathIterator(at);
}
/*------------------ Externalizable --------------------- */
/**
* The following two methods implement the Externalizable interface. We use
* Externalizable instead of Seralizable so we have full control over the data
* format, and only write out the defined coordinates
*/
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
out.writeFloat(x0);
out.writeFloat(y0);
out.writeInt(numsegs);
for (int i = 0; i < numsegs * 2; i++)
out.writeFloat(coords[i]);
}
public void readExternal(java.io.ObjectInput in) throws java.io.IOException,
ClassNotFoundException {
this.x0 = in.readFloat();
this.y0 = in.readFloat();
this.numsegs = in.readInt();
this.coords = new float[numsegs * 2];
for (int i = 0; i < numsegs * 2; i++)
coords[i] = in.readFloat();
}
/*------------------ Cloneable --------------------- */
/**
* Override the Object.clone() method so that the array gets cloned, too.
*/
public Object clone() {
try {
PolyLine copy = (PolyLine) super.clone();
if (coords != null)
copy.coords = (float[]) this.coords.clone();
return copy;
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // This should never happen
}
}
}
/*
* 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.
*/
/**
* This class implements the Transferable interface for PolyLine objects. It
* also defines a DataFlavor used to describe this data type.
*/
class TransferablePolyLine implements Transferable {
public static DataFlavor FLAVOR = new DataFlavor(PolyLine.class, "PolyLine");
static DataFlavor[] FLAVORS = new DataFlavor[] { FLAVOR };
PolyLine line; // This is the PolyLine we wrap.
public TransferablePolyLine(PolyLine line) {
this.line = line;
}
/** Return the supported flavor */
public DataFlavor[] getTransferDataFlavors() {
return FLAVORS;
}
/** Check for the one flavor we support */
public boolean isDataFlavorSupported(DataFlavor f) {
return f.equals(FLAVOR);
}
/** Return the wrapped PolyLine, if the flavor is right */
public Object getTransferData(DataFlavor f) throws UnsupportedFlavorException {
if (!f.equals(FLAVOR))
throw new UnsupportedFlavorException(f);
return line;
}
}
14. Set tree drag mode to DropMode.INSERT
import java.awt.BorderLayout;
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.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
public class DndTree {
public static void main(String args[]) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel top = new JPanel(new BorderLayout());
JLabel dragLabel = new JLabel("Drag me:");
JTextField text = new JTextField();
text.setDragEnabled(true);
top.add(dragLabel, BorderLayout.WEST);
top.add(text, BorderLayout.CENTER);
f.add(top, BorderLayout.NORTH);
final JTree tree = new JTree();
final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
tree.setTransferHandler(new TransferHandler() {
public boolean canImport(TransferHandler.TransferSupport support) {
if (!support.isDataFlavorSupported(DataFlavor.stringFlavor) || !support.isDrop()) {
return false;
}
JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
return dropLocation.getPath() != null;
}
public boolean importData(TransferHandler.TransferSupport support) {
if (!canImport(support)) {
return false;
}
JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
TreePath path = dropLocation.getPath();
Transferable transferable = support.getTransferable();
String transferData;
try {
transferData = (String) transferable.getTransferData(DataFlavor.stringFlavor);
} catch (IOException e) {
return false;
} catch (UnsupportedFlavorException e) {
return false;
}
int childIndex = dropLocation.getChildIndex();
if (childIndex == -1) {
childIndex = model.getChildCount(path.getLastPathComponent());
}
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(transferData);
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path.getLastPathComponent();
model.insertNodeInto(newNode, parentNode, childIndex);
TreePath newPath = path.pathByAddingChild(newNode);
tree.makeVisible(newPath);
tree.scrollRectToVisible(tree.getPathBounds(newPath));
return true;
}
});
JScrollPane pane = new JScrollPane(tree);
f.add(pane, BorderLayout.CENTER);
tree.setDropMode(DropMode.INSERT);
f.setSize(300, 400);
f.setVisible(true);
}
}
14. Set tree drag mode to DropMode.ON
import java.awt.BorderLayout;
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.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
public class DndTree {
public static void main(String args[]) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel top = new JPanel(new BorderLayout());
JLabel dragLabel = new JLabel("Drag me:");
JTextField text = new JTextField();
text.setDragEnabled(true);
top.add(dragLabel, BorderLayout.WEST);
top.add(text, BorderLayout.CENTER);
f.add(top, BorderLayout.NORTH);
final JTree tree = new JTree();
final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
tree.setTransferHandler(new TransferHandler() {
public boolean canImport(TransferHandler.TransferSupport support) {
if (!support.isDataFlavorSupported(DataFlavor.stringFlavor) || !support.isDrop()) {
return false;
}
JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
return dropLocation.getPath() != null;
}
public boolean importData(TransferHandler.TransferSupport support) {
if (!canImport(support)) {
return false;
}
JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
TreePath path = dropLocation.getPath();
Transferable transferable = support.getTransferable();
String transferData;
try {
transferData = (String) transferable.getTransferData(DataFlavor.stringFlavor);
} catch (IOException e) {
return false;
} catch (UnsupportedFlavorException e) {
return false;
}
int childIndex = dropLocation.getChildIndex();
if (childIndex == -1) {
childIndex = model.getChildCount(path.getLastPathComponent());
}
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(transferData);
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path.getLastPathComponent();
model.insertNodeInto(newNode, parentNode, childIndex);
TreePath newPath = path.pathByAddingChild(newNode);
tree.makeVisible(newPath);
tree.scrollRectToVisible(tree.getPathBounds(newPath));
return true;
}
});
JScrollPane pane = new JScrollPane(tree);
f.add(pane, BorderLayout.CENTER);
tree.setDropMode(DropMode.ON);
f.setSize(300, 400);
f.setVisible(true);
}
}
14. Set tree drag mode to DropMode.ON_OR_INSERT
import java.awt.BorderLayout;
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.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
public class DndTree {
public static void main(String args[]) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel top = new JPanel(new BorderLayout());
JLabel dragLabel = new JLabel("Drag me:");
JTextField text = new JTextField();
text.setDragEnabled(true);
top.add(dragLabel, BorderLayout.WEST);
top.add(text, BorderLayout.CENTER);
f.add(top, BorderLayout.NORTH);
final JTree tree = new JTree();
final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
tree.setTransferHandler(new TransferHandler() {
public boolean canImport(TransferHandler.TransferSupport support) {
if (!support.isDataFlavorSupported(DataFlavor.stringFlavor) || !support.isDrop()) {
return false;
}
JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
return dropLocation.getPath() != null;
}
public boolean importData(TransferHandler.TransferSupport support) {
if (!canImport(support)) {
return false;
}
JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
TreePath path = dropLocation.getPath();
Transferable transferable = support.getTransferable();
String transferData;
try {
transferData = (String) transferable.getTransferData(DataFlavor.stringFlavor);
} catch (IOException e) {
return false;
} catch (UnsupportedFlavorException e) {
return false;
}
int childIndex = dropLocation.getChildIndex();
if (childIndex == -1) {
childIndex = model.getChildCount(path.getLastPathComponent());
}
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(transferData);
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path.getLastPathComponent();
model.insertNodeInto(newNode, parentNode, childIndex);
TreePath newPath = path.pathByAddingChild(newNode);
tree.makeVisible(newPath);
tree.scrollRectToVisible(tree.getPathBounds(newPath));
return true;
}
});
JScrollPane pane = new JScrollPane(tree);
f.add(pane, BorderLayout.CENTER);
tree.setDropMode(DropMode.ON_OR_INSERT);
f.setSize(300, 400);
f.setVisible(true);
}
}
14. Set tree DropMode to DropMode.USE_SELECTION
import java.awt.BorderLayout;
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.DropMode;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
public class DndTree {
public static void main(String args[]) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel top = new JPanel(new BorderLayout());
JLabel dragLabel = new JLabel("Drag me:");
JTextField text = new JTextField();
text.setDragEnabled(true);
top.add(dragLabel, BorderLayout.WEST);
top.add(text, BorderLayout.CENTER);
f.add(top, BorderLayout.NORTH);
final JTree tree = new JTree();
final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
tree.setTransferHandler(new TransferHandler() {
public boolean canImport(TransferHandler.TransferSupport support) {
if (!support.isDataFlavorSupported(DataFlavor.stringFlavor) || !support.isDrop()) {
return false;
}
JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
return dropLocation.getPath() != null;
}
public boolean importData(TransferHandler.TransferSupport support) {
if (!canImport(support)) {
return false;
}
JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation();
TreePath path = dropLocation.getPath();
Transferable transferable = support.getTransferable();
String transferData;
try {
transferData = (String) transferable.getTransferData(DataFlavor.stringFlavor);
} catch (IOException e) {
return false;
} catch (UnsupportedFlavorException e) {
return false;
}
int childIndex = dropLocation.getChildIndex();
if (childIndex == -1) {
childIndex = model.getChildCount(path.getLastPathComponent());
}
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(transferData);
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path.getLastPathComponent();
model.insertNodeInto(newNode, parentNode, childIndex);
TreePath newPath = path.pathByAddingChild(newNode);
tree.makeVisible(newPath);
tree.scrollRectToVisible(tree.getPathBounds(newPath));
return true;
}
});
JScrollPane pane = new JScrollPane(tree);
f.add(pane, BorderLayout.CENTER);
tree.setDropMode(DropMode.USE_SELECTION);
f.setSize(300, 400);
f.setVisible(true);
}
}
14. Transfer both Text and Color between JTextField and JTextArea
import java.awt.Color;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
import javax.swing.text.JTextComponent;
public class DnDDemo2 {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new JPanel());
JTextField textField = new JTextField(25);
textField.setText("Let"s swing higher");
frame.add(textField);
JTextArea textArea = new JTextArea("Demonstrating\ndrag and drop");
textArea.setForeground(Color.red);
frame.add(new JScrollPane(textArea));
textArea.setDragEnabled(true);
textField.setDragEnabled(true);
TextColorTransferHandler transferHandler = new TextColorTransferHandler();
textArea.setTransferHandler(transferHandler);
textField.setTransferHandler(transferHandler);
frame.pack();
frame.setVisible(true);
}
}
class TextColorTransferHandler extends TransferHandler {
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
protected Transferable createTransferable(JComponent component) {
String text = ((JTextComponent) component).getText();
Color color = component.getForeground();
TextColor transferable = new TextColor(text, color);
return transferable;
}
public boolean canImport(JComponent c, DataFlavor[] flavors) {
return true;
}
public boolean importData(JComponent component, Transferable transferable) {
String colorMimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=java.awt.Color";
JTextComponent textComponent = (JTextComponent) component;
try {
DataFlavor colorFlavor = new DataFlavor(colorMimeType);
Color color = (Color) transferable.getTransferData(colorFlavor);
String text = (String) transferable.getTransferData(DataFlavor.stringFlavor);
textComponent.setForeground(color);
textComponent.setText(text);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
}
class TextColor implements Transferable {
private String text;
private Color color;
private DataFlavor[] flavors;
public TextColor(String text, Color color) {
String colorMimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=java.awt.Color";
DataFlavor colorFlavor = null;
try {
colorFlavor = new DataFlavor(colorMimeType);
} catch (ClassNotFoundException e) {
}
flavors = new DataFlavor[2];
flavors[0] = DataFlavor.stringFlavor;
flavors[1] = colorFlavor;
this.text = text;
this.color = color;
}
public DataFlavor[] getTransferDataFlavors() {
return (DataFlavor[]) flavors.clone();
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
for (int i = 0; i < flavors.length; i++) {
if (flavor.equals(flavors[i])) {
return true;
}
}
return false;
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (flavor.equals(flavors[0])) {
return text;
} else if (flavor.equals(flavors[1])) {
return color;
} else {
throw new UnsupportedFlavorException(flavor);
}
}
}
//Reference:
//Java 6 New Features: A Tutorial
//by Budi Kurniawan
//Brainy Software Corp. 2006
//Chapter 4 - Networking
//# ISBN-10: 0975212885
//# ISBN-13: 978-0975212882
14. Various drop actions
/*
* Copyright (c) 1995 - 2008 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:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - 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.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
/*
* DropDemo.java requires the following file:
* ListTransferHandler.java
*/
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
public class DropDemo extends JPanel implements ActionListener {
private JComboBox dropCombo;
private JList list;
public DropDemo() {
super(new GridLayout(2,1));
add(createArea());
add(createList());
}
private JPanel createList() {
DefaultListModel listModel = new DefaultListModel();
for (int i = 0; i < 10; i++) {
listModel.addElement("List Item " + i);
}
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());
dropCombo = new JComboBox(new String[] {"USE_SELECTION", "ON", "INSERT", "ON_OR_INSERT"});
dropCombo.addActionListener(this);
JPanel dropPanel = new JPanel();
dropPanel.add(new JLabel("List Drop Mode:"));
dropPanel.add(dropCombo);
JPanel panel = new JPanel(new BorderLayout());
panel.add(scrollPane, BorderLayout.CENTER);
panel.add(dropPanel, BorderLayout.SOUTH);
panel.setBorder(BorderFactory.createTitledBorder("List"));
return panel;
}
private JPanel createArea() {
String text = "Drag from or drop into this area.\nThe default action is MOVE;\nhold the Control key to COPY.";
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;
}
public void actionPerformed(ActionEvent ae) {
Object val = dropCombo.getSelectedItem();
if (val == "USE_SELECTION") {
list.setDropMode(DropMode.USE_SELECTION);
} else if (val == "ON") {
list.setDropMode(DropMode.ON);
} else if (val == "INSERT") {
list.setDropMode(DropMode.INSERT);
} else if (val == "ON_OR_INSERT") {
list.setDropMode(DropMode.ON_OR_INSERT);
}
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("DropDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new DropDemo();
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() {
//Turn off metal"s use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
/*
* Copyright (c) 1995 - 2008 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:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - 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.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
/*
* ListTransferHandler.java is used by the DropDemo example.
*/
class ListTransferHandler extends TransferHandler {
private int[] indices = null;
private int addIndex = -1; // Location where items were added
private int addCount = 0; // Number of items added.
public boolean canImport(TransferHandler.TransferSupport info) {
// Check for String flavor
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
return true;
}
protected Transferable createTransferable(JComponent c) {
return new StringSelection(exportString(c));
}
public int getSourceActions(JComponent c) {
return TransferHandler.COPY_OR_MOVE;
}
public boolean importData(TransferHandler.TransferSupport info) {
if (!info.isDrop()) {
return false;
}
JList list = (JList) info.getComponent();
DefaultListModel listModel = (DefaultListModel) list.getModel();
JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
int index = dl.getIndex();
boolean insert = dl.isInsert();
// Get the string that is being dropped.
Transferable t = info.getTransferable();
String data;
try {
data = (String) t.getTransferData(DataFlavor.stringFlavor);
} catch (Exception e) {
return false;
}
// Perform the actual import.
if (insert) {
listModel.add(index, data);
} else {
listModel.set(index, data);
}
return true;
}
protected void exportDone(JComponent c, Transferable data, int action) {
cleanup(c, action == TransferHandler.MOVE);
}
// 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;
}
}