Friday, June 11, 2010

DragandDrop in JTable

TransferHandler is used to handle the transfer of a Transferable to and from Swing components. The Transferable is used to represent data that is exchanged via a cut, copy, or paste to/from a clipboard. It is also used in drag-and-drop operations to represent a drag from a component, and a drop to a component. Swing provides functionality that automatically supports cut, copy, and paste keyboard bindings that use the functionality provided by an implementation of this class. Swing also provides functionality that automatically supports drag and drop that uses the functionality provided by an implementation of this class. The Swing developer can concentrate on specifying the semantics of a transfer primarily by setting the transferHandler property on a Swing component.

This class is implemented to provide a default behavior of transferring a component property simply by specifying the name of the property in the constructor. For example, to transfer the foreground color from one component to another either via the clipboard or a drag and drop operation a TransferHandler can be constructed with the string "foreground". The built in support will use the color returned by getForeground as the source of the transfer, and setForeground for the target of a transfer.


For Example for JTable:


import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.IOException;

public class DragandDrop extends JFrame {

public DragandDrop() {
setTitle("DnD Demo");
JTextArea tips = new JTextArea("1. Select a row in Table A. " +
"Press the row again and drag. \n " +
"As you drag the cursor icon over Table B, the row that is currently under the cursor highlights " +
"? the new data will be inserted after the selected row. \n " +
"Drop the row onto Table B. Note that the row has been removed from Table A, " +
"and now appears in Table B. \n" +
"2. Select two rows from Table A and drop onto Table B. " +
"Now there are two new rows in Table B. ");
tips.setEditable(false);
tips.setBackground(new Color(255, 255, 204));
tips.setBorder(new LineBorder(Color.orange, 5));
getContentPane().add(tips, BorderLayout.NORTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridLayout(2, 1));
panel.add(createTable("Table A"));
panel.add(createTable("Table B"));
getContentPane().add(panel, BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
}

private JPanel createTable(String tableId) {
DefaultTableModel model = new DefaultTableModel();
model.addColumn("Column 0");
model.addColumn("Column 1");
model.addColumn("Column 2");
model.addColumn("Column 3");
model.addRow(new String[]{tableId + " 00", tableId + " 01", tableId + " 02", tableId + " 03"});
model.addRow(new String[]{tableId + " 10", tableId + " 11", tableId + " 12", tableId + " 13"});
model.addRow(new String[]{tableId + " 20", tableId + " 21", tableId + " 22", tableId + " 23"});
model.addRow(new String[]{tableId + " 30", tableId + " 31", tableId + " 32", tableId + " 33"});
model.addRow(new String[]{tableId + " 40", tableId + " 41", tableId + " 42", tableId + " 43"});
model.addRow(new String[]{tableId + " 50", tableId + " 51", tableId + " 52", tableId + " 53"});
model.addRow(new String[]{tableId + " 60", tableId + " 61", tableId + " 62", tableId + " 63"});
model.addRow(new String[]{tableId + " 70", tableId + " 71", tableId + " 72", tableId + " 73"});
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());
scrollPane.getViewport().setTransferHandler(new ViewportTransferHandler());
JPanel panel = new JPanel();
panel.add(scrollPane);
panel.setBorder(BorderFactory.createTitledBorder(tableId));
return panel;
}

public static void main(String[] args) {
new DragandDrop().setVisible(true);
}

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 ndx = 0; ndx < flavors.length; ndx++) {
if (DataFlavor.stringFlavor.equals(flavors[ndx])) {
return true;
}
}
return false;
}
}

class TableTransferHandler extends StringTransferHandler {

public JTable target;
public int[] rows = null;
public int addIndex = -1; //Location where items were added

public 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 ndx = 0; ndx < rows.length; ndx++) {
for (int j = 0; j < colCount; j++) {
Object val = table.getValueAt(rows[ndx], j);
buff.append(val == null ? "" : val.toString());
if (j != colCount - 1) {
buff.append(",");
}
}
if (ndx != rows.length - 1) {
buff.append("\n");
}
}
return buff.toString();
}

protected void importString(JComponent c, String str) {
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 ndx = 0; ndx < values.length; ndx++) {
model.insertRow(index++, values[ndx].split(","));
}
//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 (rows != null && addCount > 0) {
for (int ndx = 0; ndx < rows.length; ndx++) {
if (rows[ndx] > addIndex) {
rows[ndx] += addCount;
}
}
}
}

protected void cleanup(JComponent c, boolean remove) {
JTable source = (JTable) c;
if (remove && rows != null) {
DefaultTableModel model =
(DefaultTableModel) source.getModel();
for (int ndx = rows.length - 1; ndx >= 0; ndx--) {
model.removeRow(rows[ndx]);
}
}
rows = null;
addCount = 0;
addIndex = -1;
}
}

class ViewportTransferHandler extends TransferHandler {

private JComponent getView(JComponent comp) {
JViewport viewport = (JViewport) comp;
return (JComponent) viewport.getView();
}

public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
JComponent view = getView(comp);
return view.getTransferHandler().canImport(view, transferFlavors);
}

public void exportAsDrag(JComponent comp, InputEvent e, int action) {
JComponent view = getView(comp);
view.getTransferHandler().exportAsDrag(view, e, action);
}

public void exportToClipboard(JComponent comp, Clipboard clip, int action) {
JComponent view = getView(comp);
view.getTransferHandler().exportToClipboard(view, clip, action);
}

public int getSourceActions(JComponent c) {
JComponent view = getView(c);
return view.getTransferHandler().getSourceActions(view);
}

public boolean importData(JComponent comp, Transferable t) {
JComponent view = getView(comp);
return view.getTransferHandler().importData(view, t);
}
}
}

No comments:

Post a Comment