Search code examples
javamacosfileanimationdrag-and-drop

Why is drag and drop taking time on huge files?


I created a java program that works by accepting a file that got dragged and dropped. When ever i drag small files, it works. but when i drag huge file 100MB above, it hangs till it finish processing the file. I'm using Macbook with macOS High Sierra.

public ArrayList result() {

    TransferHandler th;
    th = new TransferHandler() {
        @Override
        public boolean canImport(JComponent comp, DataFlavor[] transfarFlavors) {
            return true;
        }

        @Override
        public boolean importData(JComponent comp, Transferable t) {

            try {
                List<File> files = (List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);
                files.forEach((File file) -> {
                    String fName = file.getName();
                    String fPath = file.getAbsolutePath();
//I even added animation to show when the file is dropped, since small files are executed fast the animation doesn't show, but large files hang so no animation too.
                    ImageIcon loadPage = new ImageIcon(new ImageIcon("/Users/me/Pictures/hit.gif").getImage());
                    loadingImage.setIcon(loadPage);
                    Processor starts = new Processor();
                    try {
                        result = starts.getFile(fPath, fName);
                        setResult(result());

                        //fileNameText.setOpaque(true);
                    } catch (IOException ex) {
                        Logger.getLogger(DragnDrop.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(DragnDrop.class.getName()).log(Level.SEVERE, null, ex);
                    }
                });
            } catch (UnsupportedFlavorException | IOException ex) {
                Logger.getLogger(DragnDrop.class.getName()).log(Level.SEVERE, null, ex);
            }
            return true;
        }
    };
    DnD.setTransferHandler(th);

    return result;
}

Solution

  • To solve the problem with the blocked EDT you can use a javax.swing.SwingWorker.

    Your code is very vague about what the result of Processor.getFile() is and what happens with that result and therefore I can only make rudimentary suggestions about the result processing in the SwingWorker.

    public ArrayList<Object> result() {
    
        TransferHandler th;
        th = new TransferHandler() {
            @Override
            public boolean canImport(JComponent comp, DataFlavor[] transfarFlavors) {
                return true;
            }
    
            @Override
            public boolean importData(JComponent comp, Transferable t) {
    
                try {
                    ImageIcon loadPage = new ImageIcon(new ImageIcon("/Users/me/Pictures/hit.gif").getImage());
                    loadingImage.setIcon(loadPage);
                    List<File> files = (List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);
                    FileWorker fw = new FileWorker(files);
                    fw.execute();
                } catch (UnsupportedFlavorException | IOException ex) {
                    Logger.getLogger(DragnDrop.class.getName()).log(Level.SEVERE, null, ex);
                }
                return true;
            }
        };
        DnD.setTransferHandler(th);
    
        return null;
    }
    
    private static class FileWorker extends SwingWorker<Object, Object> {
    
        private final List<File> files;
        public FileWorker(List<File> files) {
            this.files = files;
        }
    
        @Override
        protected List<Object> doInBackground() throws Exception {
            List<Object> results = new ArrayList<>();
            files.forEach((File file) -> {
                String fName = file.getName();
                String fPath = file.getAbsolutePath();
                Processor starts = new Processor();
                try {
                    Object result = starts.getFile(fPath, fName);
                    results.add(result);
                    publish(result);
    
                } catch (IOException | InterruptedException ex) {
                    Logger.getLogger(DragnDrop.class.getName()).log(Level.SEVERE, null, ex);
                }
            });
            return results;
        }
    
        @Override
        protected void process(List<Object> chunks) {
            // here you could update UI elements with some intermediate results
        }
    
        @Override
        protected void done() {
            // here you could update UI elements with the final results
        }
    }