Search code examples
javaswingdrag-and-drop

How do I drag and drop from a Swing application to a windows explorer?


I want to drag and drop swing components to a windows explorer.

I found that answer which does the opposite that I need although the title says the opposite : Swing application -> Drag & drop to the desktop / folder

Also found that answer mentioning the OLE interface and JNI interface : https://coderanch.com/t/659365/java/Drag-Drop-Explorer

And also this thread in which OP has the exact same problem as me : https://www.dreamincode.net/forums/topic/148892-drag-and-drop-to-windows-explorer/


Solution

  • Here is an example that involves drag-n-drop of files from a JTree to a windows explorer :

    import java.awt.datatransfer.DataFlavor;
    import java.awt.datatransfer.Transferable;
    import java.awt.datatransfer.UnsupportedFlavorException;
    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Collectors;
    
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JScrollPane;
    import javax.swing.JTree;
    import javax.swing.SwingUtilities;
    import javax.swing.TransferHandler;
    import javax.swing.tree.DefaultMutableTreeNode;
    import javax.swing.tree.DefaultTreeModel;
    import javax.swing.tree.TreePath;
    
    public class FileBrowser implements Runnable {
    
        private DefaultMutableTreeNode root;
    
        private DefaultTreeModel treeModel;
    
        private JTree tree;
    
        @Override
        public void run() {
            JFrame frame = new JFrame("File Browser");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            File fileRoot = File.listRoots()[0];
            root = new DefaultMutableTreeNode(new FileNode(fileRoot));
            treeModel = new DefaultTreeModel(root);
    
            tree = new JTree(treeModel);
            tree.setShowsRootHandles(true);
            tree.setDragEnabled(true);
            tree.setTransferHandler(new FileTransferHandler());
            JScrollPane scrollPane = new JScrollPane(tree);
    
            frame.add(scrollPane);
            frame.setLocationByPlatform(true);
            frame.setSize(640, 480);
            frame.setVisible(true);
    
            CreateChildNodes ccn = new CreateChildNodes(fileRoot, root);
            new Thread(ccn).start();
        }
    
        public class CreateChildNodes implements Runnable {
    
            private DefaultMutableTreeNode root;
    
            private File fileRoot;
    
            public CreateChildNodes(File fileRoot, DefaultMutableTreeNode root) {
                this.fileRoot = fileRoot;
                this.root = root;
            }
    
            @Override
            public void run() {
                createChildren(fileRoot, root);
            }
    
            private void createChildren(File fileRoot, DefaultMutableTreeNode node) {
                File[] files = fileRoot.listFiles();
                if (files == null)
                    return;
    
                for (File file : files) {
                    DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(new FileNode(file));
                    node.add(childNode);
                    if (file.isDirectory()) {
                        createChildren(file, childNode);
                    }
                }
            }
    
        }
    
        public class FileNode {
    
            private File file;
    
            public FileNode(File file) {
                this.file = file;
            }
    
            @Override
            public String toString() {
                String name = file.getName();
                if (name.equals("")) {
                    return file.getAbsolutePath();
                } else {
                    return name;
                }
            }
        }
    
        private class FileTransferHandler extends TransferHandler {
    
            private static final long serialVersionUID = 1L;
    
            @Override
            protected Transferable createTransferable(JComponent c) {
                JTree list = (JTree) c;
                List<File> files = new ArrayList<File>();
                for (TreePath path : list.getSelectionPaths()) {
                    files.add(new File(Arrays.stream(path.getPath()).map(Object::toString).collect(Collectors.joining(File.separator))));
                }
                return new FileTransferable(files);
            }
    
            @Override
            public int getSourceActions(JComponent c) {
                return MOVE;
            }
        }
    
        private class FileTransferable implements Transferable {
    
            private List<File> files;
    
            public FileTransferable(List<File> files) {
                this.files = files;
            }
    
            public DataFlavor[] getTransferDataFlavors() {
                return new DataFlavor[] { DataFlavor.javaFileListFlavor };
            }
    
            public boolean isDataFlavorSupported(DataFlavor flavor) {
                return flavor.equals(DataFlavor.javaFileListFlavor);
            }
    
            public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
                if (!isDataFlavorSupported(flavor)) {
                    throw new UnsupportedFlavorException(flavor);
                }
                return files;
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new FileBrowser());
        }
    
    }