rogerthat rogerthat - 6 days ago 5
Java Question

drag and drop files from OS into JTable java

Can someone show me what I'm doing wrong? I was able to get drag and drop working with a regular panel but now trying with a table and I can't sort it out. I'm getting confused with the Points and DropTargets. Dont mind the "Add" button. I feel like I need to deal with the DnD first.

public class Table extends JFrame implements ActionListener {

private JTable table;
private JScrollPane scroll;
private JButton add;
private JFileChooser choose;
private JMenuBar menubar;
private JMenu menu;
private JMenuItem file;
private DefaultTableModel tm = new DefaultTableModel(new String[] { "File",
"File Type", "Size", "Status" }, 2);

public Table() {

// String column [] = {"Filename ","File Type", "Size", "Status" };
/*
* Object[][] data = { {"File1", ".jpg","32 MB", "Not Processed"},
* {"File2", ".txt"," 5 Kb", "Not Processed"}, {"File3", ".doc","3 Kb",
* "Not Processed"},
* };
*/

table = new JTable();
table.setModel(tm);
table.setFillsViewportHeight(true);
table.setPreferredSize(new Dimension(500, 300));

scroll = new JScrollPane(table);

table.setDropTarget(new DropTarget() {
@Override
public synchronized void drop(DropTargetDropEvent dtde) {

Point point = dtde.getLocation();
int column = table.columnAtPoint(point);
int row = table.rowAtPoint(point);

dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
Transferable t = dtde.getTransferable();
List fileList = null;
try {
fileList = (List) t
.getTransferData(DataFlavor.javaFileListFlavor);
} catch (UnsupportedFlavorException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
File f = (File) fileList.get(0);
table.setValueAt(f.getAbsolutePath(), row, column);
table.setValueAt(f.length(), row, column + 1);
super.drop(dtde);
}
});
scroll.setDropTarget(new DropTarget() {
@Override
public synchronized void drop(DropTargetDropEvent dtde) {
Point point = dtde.getLocation();
int column = table.columnAtPoint(point);
int row = table.rowAtPoint(point);

dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
Transferable t = dtde.getTransferable();
List fileList = null;
try {
fileList = (List) t
.getTransferData(DataFlavor.javaFileListFlavor);
} catch (UnsupportedFlavorException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
File f = (File) fileList.get(0);
table.setValueAt(f.getAbsolutePath(), row, column);
table.setValueAt(f.length(), row, column + 1);
// handle drop outside current table (e.g. add row)
super.drop(dtde);
}
});

add(scroll, BorderLayout.CENTER);

menubar = new JMenuBar();
menu = new JMenu("File");
file = new JMenuItem("file");
menu.add(file);
// menubar.add(menu);
add(menu, BorderLayout.NORTH);

ImageIcon icon = new ImageIcon("lock_icon.png");

add = new JButton("Add", icon);
add.addActionListener(this);

JFileChooser choose = new JFileChooser();
choose.addActionListener(this);
}

@Override
public void actionPerformed(ActionEvent e) {
JButton clicked = (JButton) e.getSource();

int returnValue = 0;

if (clicked == add) {
choose = new JFileChooser();
choose.showOpenDialog(null);

if (returnValue == JFileChooser.APPROVE_OPTION) {
File file = choose.getSelectedFile();
file.getAbsolutePath();

}

}

}

public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {

Table t = new Table();

t.setDefaultCloseOperation(EXIT_ON_CLOSE);
t.pack();
t.setSize(600, 200);
t.setVisible(true);
t.setTitle("ZipLock");
t.setIconImage(null);

}
});

}

}

Answer

I personally would ditch the drop target on the scroll pane, it's going to cause you to many problems.

Your drop method is a little queezy...

This is a bad idea....

List fileList = null;
try {
    fileList = (List) t
        .getTransferData(DataFlavor.javaFileListFlavor);
} catch (UnsupportedFlavorException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
File f = (File) fileList.get(0);
table.setValueAt(f.getAbsolutePath(), row, column);
table.setValueAt(f.length(), row, column + 1);

Basically, you try and extract the file list from the transferable and regardless of the success of the operation, you try and use it ?! You do no validation of the returned value at all...

You're drop code generally doesn't really care about what column the drop occurred on, as you have name and size columns already, so I'd actually ignore that altogether.

As for the row, now you have two choices. Either you add a new row when the user does not drop on an existing one or you reject the attempt.

Reject drag's "outside" of table

(Or reject drags that don't call over an existing row)

To reject the operation while the user is dragging, you need to override the dragOver method...

@Override
public synchronized void dragOver(DropTargetDragEvent dtde) {
    Point point = dtde.getLocation();
    int row = table.rowAtPoint(point);
    if (row < 0) {
        dtde.rejectDrag();
        table.clearSelection();
    } else {
        dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
        table.setRowSelectionInterval(row, row);
    }
}

Now, I'm begin a little smart here (and not in the clever way). Basically, if the user has dragged over a row, I've highlighted it. This makes it a little more obvious where the drop is going.

In your drop method, I would also make some additional checks...

@Override
public synchronized void drop(DropTargetDropEvent dtde) {    
    Point point = dtde.getLocation();
    int row = table.rowAtPoint(point);
    if (row >= 0) {
        if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
            dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
            Transferable t = dtde.getTransferable();
            List fileList = null;
            try {
                fileList = (List) t.getTransferData(DataFlavor.javaFileListFlavor);
                if (fileList.size() > 0) {
                    table.clearSelection();
                    Point point = dtde.getLocation();
                    int row = table.rowAtPoint(point);
                    DefaultTableModel model = (DefaultTableModel) table.getModel();
                    model.setValueAt(f.getAbsolutePath(), row, 0);
                    model.setValueAt(f.length(), row, 2);
                }
            } catch (UnsupportedFlavorException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            dtde.rejectDrop();
        }
    } else {
        dtde.rejectDrop();
    }
}

Accept Drag's "outside" of the table

The process is relativly the same, except now we can throw away the conditions that would have otherwise caused use to reject the drag/drop (obviously)

@Override
public synchronized void dragOver(DropTargetDragEvent dtde) {
    Point point = dtde.getLocation();
    int row = table.rowAtPoint(point);
    if (row < 0) {
        table.clearSelection();
    } else {
        table.setRowSelectionInterval(row, row);
    }
    dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
}

And the drop method

@Override
public synchronized void drop(DropTargetDropEvent dtde) {    
    if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
        dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
        Transferable t = dtde.getTransferable();
        List fileList = null;
        try {
            fileList = (List) t.getTransferData(DataFlavor.javaFileListFlavor);
            if (fileList.size() > 0) {
                table.clearSelection();
                Point point = dtde.getLocation();
                int row = table.rowAtPoint(point);
                DefaultTableModel model = (DefaultTableModel) table.getModel();
                for (Object value : fileList) {
                    if (value instanceof File) {
                        File f = (File) value;
                        if (row < 0) {
                            System.out.println("addRow");
                            model.addRow(new Object[]{f.getAbsolutePath(), "", f.length(), "", ""});
                        } else {
                            System.out.println("insertRow " + row);
                            model.insertRow(row, new Object[]{f.getAbsolutePath(), "", f.length(), "", ""});
                            row++;
                        }
                    }
                }
            }
        } catch (UnsupportedFlavorException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } else {
        dtde.rejectDrop();
    }
}

Note. This will insert rows at the drop point, push all the existing rows down OR if not dropped on an existing row, will add them to the end...

TEST CODE

This a full running example I used to test the code...

public class DropTable {

    public static void main(String[] args) {
        new DropTable();
    }

    public DropTable() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new DropPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class DropPane extends JPanel {

        private JTable table;
        private JScrollPane scroll;
        private DefaultTableModel tm = new DefaultTableModel(new String[]{"File", "File Type", "Size", "Status"}, 0);

        public DropPane() {
            table = new JTable();
            table.setShowGrid(true);
            table.setShowHorizontalLines(true);
            table.setShowVerticalLines(true);
            table.setGridColor(Color.GRAY);

            table.setModel(tm);
            table.setFillsViewportHeight(true);
            table.setPreferredSize(new Dimension(500, 300));

            scroll = new JScrollPane(table);

            table.setDropTarget(new DropTarget() {
                @Override
                public synchronized void dragOver(DropTargetDragEvent dtde) {
                    Point point = dtde.getLocation();
                    int row = table.rowAtPoint(point);
                    if (row < 0) {
                        table.clearSelection();
                    } else {
                        table.setRowSelectionInterval(row, row);
                    }
                    dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
                }

                @Override
                public synchronized void drop(DropTargetDropEvent dtde) {
                    if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                        dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
                        Transferable t = dtde.getTransferable();
                        List fileList = null;
                        try {
                            fileList = (List) t.getTransferData(DataFlavor.javaFileListFlavor);
                            if (fileList.size() > 0) {
                                table.clearSelection();
                                Point point = dtde.getLocation();
                                int row = table.rowAtPoint(point);
                                DefaultTableModel model = (DefaultTableModel) table.getModel();
                                for (Object value : fileList) {
                                    if (value instanceof File) {
                                        File f = (File) value;
                                        if (row < 0) {
                                            model.addRow(new Object[]{f.getAbsolutePath(), "", f.length(), "", ""});
                                        } else {
                                            model.insertRow(row, new Object[]{f.getAbsolutePath(), "", f.length(), "", ""});
                                            row++;
                                        }
                                    }
                                }
                            }
                        } catch (UnsupportedFlavorException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    } else {
                        dtde.rejectDrop();
                    }
                }

            });

            add(scroll, BorderLayout.CENTER);
        }
    }
}
Comments