[ajug-members] A Swing Question

J. Talafous jtalafous at gmail.com
Tue Jul 31 09:46:38 EDT 2007


Has anybody ever gotten Swing to drag and drop *multiple* rows in a
table?  Transferring a single row works fine.  Whenever you click to
start the drag, it resets the multiple selection.  It appears that
there is a conflict between the mouse listeners.  I'd even settle on
putting the drag on another key.  Someone in the Sun forums tried, but
it does not seem to work (code below).  Any ideas?  Is there a right
way to do this, without modifying tableUI?.

Joe

package dnd.table;

import java.awt.GridLayout;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.event.MouseEvent;
import java.util.Vector;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.TransferHandler;
import javax.swing.event.MouseInputAdapter;
import javax.swing.table.DefaultTableModel;

/**
 * Demonstrate multiple selection drag and drop, use ALT key to drag
 *
 * @author Dan Galitsky
 * @version 1.0
 */
public class TableDNDTest extends JFrame {

    public static DataFlavor listFlavor = new
DataFlavor(DataFlavor.javaJVMLocalObjectMimeType +
";class=java.util.List", "List");

    public static DataObjectTransferHandler dndHandler = new
DataObjectTransferHandler();
    protected static TableDNDRecognizer dndRecognizer = new
TableDNDRecognizer();
    public static boolean isDragged = false;

    public TableDNDTest() {
        super("TableDNDTest");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new GridLayout(1, 2));

        Vector<Vector<String>> tableData = new Vector<Vector<String>>();
        Vector<String> dataObject;
        for (int i = 10; i > 0; i--) {
            dataObject = new Vector<String>();
            for (int j = 0; j < 4; j++) {
                dataObject.add("data " + i + "," + j);
            }
            tableData.add(dataObject);
        }

        Vector<String> columns = new Vector<String>();
        columns.add(" ");
        columns.add("Name");
        columns.add("Size");
        columns.add(" Last modified ");
        DefaultTableModel model = new DefaultTableModel(tableData, columns);

        JTable table = new JTable(model) {

            @Override
            public void changeSelection(int rowIndex, int columnIndex,
boolean toggle, boolean extend) {
                if (!isDragged) {
                    super.changeSelection(rowIndex, columnIndex,
toggle, extend);
                }
            }
        };
        table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        table.setTransferHandler(dndHandler);
        table.setDropTarget(new DropTarget(table,
DataObjectTransferHandler.getDropHandler()));
        table.addMouseListener(dndRecognizer);
        table.addMouseMotionListener(dndRecognizer);
        getContentPane().add(new JScrollPane(table));

        // Create second table

        tableData = new Vector<Vector<String>>();
        for (int i = 10; i > 0; i--) {
            dataObject = new Vector<String>();
            for (int j = 0; j < 4; j++) {
                dataObject.add("data^ " + i + "," + j);
            }
            tableData.add(dataObject);
        }
        model = new DefaultTableModel(tableData, columns);
        JTable table2 = new JTable(model) {

            @Override
            public void changeSelection(int rowIndex, int columnIndex,
boolean toggle, boolean extend) {
                if (!isDragged) {
                    super.changeSelection(rowIndex, columnIndex,
toggle, extend);
                }
            }
        };
        table2.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        table2.setTransferHandler(dndHandler);
        table2.setDropTarget(new DropTarget(table2,
DataObjectTransferHandler.getDropHandler()));
        table2.addMouseListener(dndRecognizer);
        table2.addMouseMotionListener(dndRecognizer);

        getContentPane().add(new JScrollPane(table2));
        pack();
        setLocationRelativeTo(null);

    }

    public static void main(String[] args) {
        TableDNDTest applocation = new TableDNDTest();
        applocation.show();
    }
}// End of ListDNDTest

class TableDNDRecognizer extends MouseInputAdapter {

    private boolean recognized;
    protected Point pressedPoint;

    @Override
    public void mousePressed(MouseEvent e) {
        pressedPoint = e.getPoint();
        System.out.println("mouse pressed at " + pressedPoint);
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        Point p = e.getPoint();
        System.out.println("mouse dragged at " + p);
        if (!recognized && e.isAltDown() && ((Math.abs(pressedPoint.x
- p.x) > 5) || (Math.abs(pressedPoint.y - p.y) > 5))) {
            TableDNDTest.isDragged = true;
            System.out.println("isDragged = " + TableDNDTest.isDragged);
            recognized = true;
            JComponent c = (JComponent) e.getSource();
            TransferHandler th = c.getTransferHandler();
            if (th != null) {
                th.exportAsDrag(c, e, e.isControlDown() ?
DnDConstants.ACTION_COPY : DnDConstants.ACTION_MOVE);
            }// if
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        System.out.println("isDragged = " + true);
        recognized = false;
        TableDNDTest.isDragged = false;
        System.out.println("isDragged = " + TableDNDTest.isDragged);
        pressedPoint = null;
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
package dnd.table;

import java.awt.Component;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.io.Serializable;
import java.util.List;
import java.util.Vector;

import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.TransferHandler;
import javax.swing.table.DefaultTableModel;

/**
 */
public class DataObjectTransferHandler extends TransferHandler {

    protected Point dragPoint;
    protected Point dropPoint;
    protected Component dragComponent;
    protected Component dropComponent;

    public Point getDropPoint() {
        return dropPoint;
    }

    public void setDropPoint(Point dropPoint) {
        this.dropPoint = dropPoint;
    }

    public Component getDragComponent() {
        return dragComponent;
    }

    public void setDragComponent(Component dragComponent) {
        this.dragComponent = dragComponent;
    }

    public Point getDragPoint() {
        return dragPoint;
    }

    public void setDragPoint(Point dragPoint) {
        this.dragPoint = dragPoint;
    }

    public Component getDropComponent() {
        return dropComponent;
    }

    public void setDropComponent(Component dropComponent) {
        this.dropComponent = dropComponent;
    }

    @Override
    public int getSourceActions(JComponent c) {
        return DnDConstants.ACTION_COPY_OR_MOVE;
    }

    @Override
    public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
        if (comp.isEnabled() && (comp instanceof JTable)) {
            for (int i = 0; i < transferFlavors.length; i++) {
                if (transferFlavors[i].equals(TableDNDTest.listFlavor)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public void exportAsDrag(JComponent comp, InputEvent e, int action) {
        setDragComponent(comp);
        setDragPoint(((MouseEvent) e).getPoint());
        super.exportAsDrag(comp, e, action);
    }

    @Override
    protected Transferable createTransferable(JComponent c) {
        Transferable t = null;
        if (c instanceof JTable) {
            JTable table = (JTable) c;
            int[] selection = table.getSelectedRows();
            Vector selectedRows = new Vector();
            for (int j = 0; j < selection.length; j++) {
                selectedRows.add(((DefaultTableModel)
table.getModel()).getDataVector().get(selection[j]));
            }
            t = new ListTransferable(selectedRows);
        }
        return t;
    }

    @Override
    public boolean importData(JComponent comp, Transferable t) {
        if (canImport(comp, t.getTransferDataFlavors())) {
            try {
                if (getDragComponent() != comp) {
                    List list = (List)
t.getTransferData(TableDNDTest.listFlavor);
                    JTable table = (JTable) comp;
                    DefaultTableModel model = ((DefaultTableModel)
table.getModel());
                    int insertRow;
                    if (getDropPoint() != null) {
                        insertRow = table.rowAtPoint(getDropPoint());
                    }
                    else {
                        insertRow = table.getSelectedRow();
                    }

                    for (int i = 0; i < list.size(); i++) {
                        model.insertRow(insertRow + i, (Vector) list.get(i));
                    }

                    table.getSelectionModel().clearSelection();

table.getSelectionModel().setSelectionInterval(insertRow, insertRow +
list.size() - 1);
                    table.requestFocus();
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }// if
        return false;
    }

    @Override
    protected void exportDone(JComponent source, Transferable data,
int action) {
        if (action == DnDConstants.ACTION_MOVE) {
            try {
                List list = (List)
data.getTransferData(TableDNDTest.listFlavor);
                JTable table = (JTable) source;
                DefaultTableModel model = ((DefaultTableModel)
table.getModel());
                if (source != getDropComponent()) {
                    int index;
                    for (int i = 0; i < list.size(); i++) {
                        index = model.getDataVector().indexOf(list.get(i));
                        model.removeRow(index);
                    }
                }
                else {
                    int index;
                    int insertRow = table.rowAtPoint(getDropPoint());
                    for (int i = 0; i < list.size(); i++) {
                        index = model.getDataVector().indexOf(list.get(i));
                        model.moveRow(index, index, insertRow + i);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }// end if
    }

    protected static DropHandler dropHandler = new DropHandler();

    public static DropHandler getDropHandler() {
        return dropHandler;
    }

    /**
     *
     */
    protected static class DropHandler implements DropTargetListener,
Serializable {

        /**
         *
         */
        private static final long serialVersionUID = 1L;
        private boolean canImport;

        private boolean actionSupported(int action) {
            return (action & (DnDConstants.ACTION_COPY_OR_MOVE |
DnDConstants.ACTION_LINK)) != DnDConstants.ACTION_NONE;
        }

        // --- DropTargetListener methods -----------------------------------

        public void dragEnter(DropTargetDragEvent e) {
            System.out.println("entered drop target");
            DataFlavor[] flavors = e.getCurrentDataFlavors();

            JComponent c = (JComponent) e.getDropTargetContext().getComponent();
            TransferHandler importer = c.getTransferHandler();

            if (importer != null && importer.canImport(c, flavors)) {
                canImport = true;
            }
            else {
                canImport = false;
            }

            int dropAction = e.getDropAction();

            if (canImport && actionSupported(dropAction)) {
                e.acceptDrag(dropAction);
            }
            else {
                e.rejectDrag();
            }
        }

        public void dragOver(DropTargetDragEvent e) {
            System.out.println("over drop target");
            int dropAction = e.getDropAction();

            if (canImport && actionSupported(dropAction)) {
                JTable table = (JTable) e.getDropTargetContext().getComponent();
                int row = table.rowAtPoint(e.getLocation());
                table.getSelectionModel().setSelectionInterval(row, row);
                e.acceptDrag(dropAction);
            }
            else {
                e.rejectDrag();
            }
        }

        public void dragExit(DropTargetEvent e) {
            System.out.println("exitted drop target");

        }

        public void drop(DropTargetDropEvent e) {
            System.out.println("dropped");
            int dropAction = e.getDropAction();

            JComponent c = (JComponent) e.getDropTargetContext().getComponent();
            DataObjectTransferHandler importer =
(DataObjectTransferHandler) c.getTransferHandler();

            if (canImport && importer != null && actionSupported(dropAction)) {
                e.acceptDrop(dropAction);

                try {
                    Transferable t = e.getTransferable();
                    importer.setDropPoint(e.getLocation());
                    importer.setDropComponent(c);
                    e.dropComplete(importer.importData(c, t));
                } catch (RuntimeException re) {
                    e.dropComplete(false);
                }
            }
            else {
                e.rejectDrop();
            }
        }

        public void dropActionChanged(DropTargetDragEvent e) {
            int dropAction = e.getDropAction();

            if (canImport && actionSupported(dropAction)) {
                e.acceptDrag(dropAction);
            }
            else {
                e.rejectDrag();
            }
        }
    }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
package dnd.table;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class ListTransferable implements Transferable {

    List data;

    public ListTransferable(List data) {
        this.data = data;
    }

    public ListTransferable(Object[] data) {
        this.data = Arrays.asList(data);
    }

    public Object getTransferData(DataFlavor flavor) throws
UnsupportedFlavorException, IOException {
        if (isDataFlavorSupported(flavor)) {
            return data;
        }
        else {
            throw new UnsupportedFlavorException(flavor);
        }
    }

    public DataFlavor[] getTransferDataFlavors() {
        return new DataFlavor[] { TableDNDTest.listFlavor };
    }

    public boolean isDataFlavorSupported(DataFlavor flavor) {
        DataFlavor[] flavors = getTransferDataFlavors();
        for (int i = 0; i < flavors.length; i++) {
            if (flavors[i].equals(flavor)) {
                return true;
            }
        }
        return false;
    }
}



More information about the ajug-members mailing list