如何在Java中从目录拖放文件

11
我希望实现从目录(例如某人的硬盘驱动器)拖放文件,但我无法弄清如何做到这一点。我已经阅读了Java API,但它讨论的是颜色选择器和在列表之间拖放,而不是如何从计算机文件系统中拖放文件并将其放入我的应用程序中。我尝试编写TransferHandler类和鼠标事件以便在拖动开始时进行操作,但似乎没有什么作用。现在我只是让我的JFileChooser设置为启用拖放,但如何放置呢?
非常感谢任何信息或指向正确方向的提示。
  import javax.swing.*;

  import java.awt.BorderLayout;
 import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;

import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;

 public class FileChooserDemo
 extends JPanel
 implements ActionListener 
  {

JLabel selectedFileLabel;
 JList selectedFilesList;
 JLabel returnCodeLabel;

 public FileChooserDemo() 
    {
 super();
 createContent();
 }


void initFrameContent() 
    {
        JPanel closePanel = new JPanel();
        add(closePanel, BorderLayout.SOUTH);
}


 private void createContent()
    {
 setLayout(new BorderLayout());

        JPanel NorthPanel = new JPanel();

     JMenuBar menuBar = new JMenuBar();
        JMenu menu = new JMenu("File");
        JMenuItem quit = new JMenuItem("Quit");

        menuBar.add(menu);
        menu.add(quit);

        NorthPanel.add(menu,BorderLayout.NORTH);


  JPanel buttonPanel = new JPanel(new GridLayout(7,1 ));
  JButton openButton = new JButton("Open...");
  openButton.setActionCommand("OPEN");
  openButton.addActionListener(this);
 buttonPanel.add(openButton);

 JButton saveButton = new JButton("Save...");
 saveButton.setActionCommand("SAVE");
 saveButton.addActionListener(this);
 buttonPanel.add(saveButton);




  JButton delete = new JButton("Delete");
  delete.addActionListener(this);
  delete.setActionCommand("DELETE");
  buttonPanel.add(delete);

 add(buttonPanel, BorderLayout.WEST);



 // create a panel to display the selected file(s) and the return code
 JPanel displayPanel = new JPanel(new BorderLayout()); 
 selectedFileLabel = new JLabel("-");

 selectedFileLabel.setBorder(BorderFactory.createTitledBorder
 ("Selected File/Directory   "));

 displayPanel.add(selectedFileLabel, BorderLayout.NORTH);

 selectedFilesList = new JList();
 JScrollPane sp = new JScrollPane(selectedFilesList);
 sp.setBorder(BorderFactory.createTitledBorder("Selected Files "));
 MouseListener listener = new MouseAdapter()
 {
   public void mousePressed(MouseEvent me)
   {
       JComponent comp = (JComponent) me.getSource();
       TransferHandler handler = comp.getTransferHandler();
       handler.exportAsDrag(comp, me, TransferHandler.MOVE);   
   }
 };
 selectedFilesList.addMouseListener(listener);

 displayPanel.add(sp);

 returnCodeLabel = new JLabel("");
 returnCodeLabel.setBorder(BorderFactory.createTitledBorder("Return Code"));
 displayPanel.add(returnCodeLabel, BorderLayout.SOUTH);

 add(displayPanel);
}


 public void actionPerformed(ActionEvent e)
    {
          int option = 0;
 File selectedFile = null;
 File[] selectedFiles = new File[0];

 if (e.getActionCommand().equals("CLOSE"))
      {
   System.exit(0);
 }
 else if (e.getActionCommand().equals("OPEN"))
        {
     JFileChooser chooser = new JFileChooser();
        chooser.setDragEnabled(true);
        chooser.setMultiSelectionEnabled(true);
     option = chooser.showOpenDialog(this);
     selectedFiles = chooser.getSelectedFiles();
   }
 else if (e.getActionCommand().equals("SAVE"))
        {
     JFileChooser chooser = new JFileChooser();
     option = chooser.showSaveDialog(this);
     selectedFiles = chooser.getSelectedFiles();
   }

 // display the selection and return code
 if (selectedFile != null)
   selectedFileLabel.setText(selectedFile.toString());
 else
   selectedFileLabel.setText("null");
 DefaultListModel listModel = new DefaultListModel();
 for (int i =0; i < selectedFiles.length; i++)
   listModel.addElement(selectedFiles[i]);

 selectedFilesList.setModel(listModel);
 returnCodeLabel.setText(Integer.toString(option));
 }

 public static void main(String[] args) 
    {
 SwingUtilities.invokeLater
 (new Runnable()
       {
    public void run()
         {
      FileChooserDemo app = new FileChooserDemo();
      app.initFrameContent();
      JFrame frame = new JFrame("LoquetUP");
      frame.getContentPane().add(app);
         frame.setDefaultCloseOperation(3);
         frame.setSize(600,400);
         frame.setResizable(false);
         frame.setLocationRelativeTo(null);

      //frame.pack();
      frame.setVisible(true);
    }
  });
 }

}

1
为什么这个 D'n'D 代码从 java.awt.dndimport nothing - Andrew Thompson
因为我删除了我的transferHandler和mouselistener代码。 - rogerthat
看一下这个Stack Overflow问题。我认为它包含了你所需要的一些内容。 - Thorn
@Thorn,在Java 1.7中有什么使得这段代码不同的地方吗? - rogerthat
2个回答

26

这是我的想法。在本例中,我使用了“传统”的拖放API。它有一些额外的“绘画”调整,只是为了展示你可能能够做什么。

在此输入图片描述在此输入图片描述

这个例子不能扫描被拖放到上面的文件夹,所以任何文件夹都只会被视为单个文件,但我相信你可以解决它。

public class TestDragNDropFiles {

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

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

                JFrame frame = new JFrame("Testing");
                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 DropTarget dropTarget;
        private DropTargetHandler dropTargetHandler;
        private Point dragPoint;

        private boolean dragOver = false;
        private BufferedImage target;

        private JLabel message;

        public DropPane() {
            try {
                target = ImageIO.read(new File("target.png"));
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            setLayout(new GridBagLayout());
            message = new JLabel();
            message.setFont(message.getFont().deriveFont(Font.BOLD, 24));
            add(message);

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        protected DropTarget getMyDropTarget() {
            if (dropTarget == null) {
                dropTarget = new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, null);
            }
            return dropTarget;
        }

        protected DropTargetHandler getDropTargetHandler() {
            if (dropTargetHandler == null) {
                dropTargetHandler = new DropTargetHandler();
            }
            return dropTargetHandler;
        }

        @Override
        public void addNotify() {
            super.addNotify();
            try {
                getMyDropTarget().addDropTargetListener(getDropTargetHandler());
            } catch (TooManyListenersException ex) {
                ex.printStackTrace();
            }
        }

        @Override
        public void removeNotify() {
            super.removeNotify();
            getMyDropTarget().removeDropTargetListener(getDropTargetHandler());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (dragOver) {
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setColor(new Color(0, 255, 0, 64));
                g2d.fill(new Rectangle(getWidth(), getHeight()));
                if (dragPoint != null && target != null) {
                    int x = dragPoint.x - 12;
                    int y = dragPoint.y - 12;
                    g2d.drawImage(target, x, y, this);
                }
                g2d.dispose();
            }
        }

        protected void importFiles(final List files) {
            Runnable run = new Runnable() {
                @Override
                public void run() {
                    message.setText("You dropped " + files.size() + " files");
                }
            };
            SwingUtilities.invokeLater(run);
        }

        protected class DropTargetHandler implements DropTargetListener {

            protected void processDrag(DropTargetDragEvent dtde) {
                if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                    dtde.acceptDrag(DnDConstants.ACTION_COPY);
                } else {
                    dtde.rejectDrag();
                }
            }

            @Override
            public void dragEnter(DropTargetDragEvent dtde) {
                processDrag(dtde);
                SwingUtilities.invokeLater(new DragUpdate(true, dtde.getLocation()));
                repaint();
            }

            @Override
            public void dragOver(DropTargetDragEvent dtde) {
                processDrag(dtde);
                SwingUtilities.invokeLater(new DragUpdate(true, dtde.getLocation()));
                repaint();
            }

            @Override
            public void dropActionChanged(DropTargetDragEvent dtde) {
            }

            @Override
            public void dragExit(DropTargetEvent dte) {
                SwingUtilities.invokeLater(new DragUpdate(false, null));
                repaint();
            }

            @Override
            public void drop(DropTargetDropEvent dtde) {

                SwingUtilities.invokeLater(new DragUpdate(false, null));

                Transferable transferable = dtde.getTransferable();
                if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                    dtde.acceptDrop(dtde.getDropAction());
                    try {

                        List transferData = (List) transferable.getTransferData(DataFlavor.javaFileListFlavor);
                        if (transferData != null && transferData.size() > 0) {
                            importFiles(transferData);
                            dtde.dropComplete(true);
                        }

                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                } else {
                    dtde.rejectDrop();
                }
            }
        }

        public class DragUpdate implements Runnable {

            private boolean dragOver;
            private Point dragPoint;

            public DragUpdate(boolean dragOver, Point dragPoint) {
                this.dragOver = dragOver;
                this.dragPoint = dragPoint;
            }

            @Override
            public void run() {
                DropPane.this.dragOver = dragOver;
                DropPane.this.dragPoint = dragPoint;
                DropPane.this.repaint();
            }
        }

    }
}

3
收藏此页面只是为了这个答案。非常好,谢谢!1+ - Hovercraft Full Of Eels
1
@healix 抱歉,我通常不包含它们,因为这会占用可以用于示例的空间。你使用什么编辑器?在Netbeans中,ctrl+shift+I将修复导入。 - MadProgrammer
@MadProgrammer 我正在使用 Eclipse。应该没问题。另外,有没有关于拖放更多学习的建议? - rogerthat
1
@bric3 首先,这使它成为一个自包含的工作单元 - 你可以手动调用“注册”和“注销”的工作流程,但你会多久忘记执行它呢?此外,由于存在许多强引用传递,这是另一层附加保障,确保我们不会设置一个组件无法进行垃圾回收的场景(或者至少降低风险)。 - MadProgrammer
1
@bric3 不是特别的,我觉得它在这种工作流程中很有用,因为它是唯一一个在组件被添加或从其父级移除时通知你的地方。 - MadProgrammer
显示剩余17条评论

8

您需要尝试拖放并查看在拖动文件时有哪些可用的选项。如果在自定义TransferHandler中进行此操作,您将惊喜地发现其中一种Flavor是,这表示该项可以简单地用作。尝试一下,您会发现它确实有效!

关于您发布的代码的审查说明,我没有看到您尝试使用TransferHandler的任何代码,所以很难说您可能做错了什么。

编辑1
您似乎正在尝试使用MouseListener进行拖放操作,而我不熟悉这种用法。您能否展示一个教程参考,告诉您要这样做吗?

编辑2

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

import javax.swing.*;

@SuppressWarnings("serial")
public class FileDragDemo extends JPanel {
   private JList list = new JList();

   public FileDragDemo() {
      list.setDragEnabled(true);
      list.setTransferHandler(new FileListTransferHandler(list));

      add(new JScrollPane(list));
   }

   private static void createAndShowGui() {
      FileDragDemo mainPanel = new FileDragDemo();

      JFrame frame = new JFrame("FileDragDemo");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

@SuppressWarnings("serial")
class FileListTransferHandler extends TransferHandler {
   private JList list;

   public FileListTransferHandler(JList list) {
      this.list = list;
   }

   public int getSourceActions(JComponent c) {
      return COPY_OR_MOVE;
   }

   public boolean canImport(TransferSupport ts) {
      return ts.isDataFlavorSupported(DataFlavor.javaFileListFlavor);
   }

   public boolean importData(TransferSupport ts) {
      try {
         @SuppressWarnings("rawtypes")
         List data = (List) ts.getTransferable().getTransferData(
               DataFlavor.javaFileListFlavor);
         if (data.size() < 1) {
            return false;
         }

         DefaultListModel listModel = new DefaultListModel();
         for (Object item : data) {
            File file = (File) item;
            listModel.addElement(file);
         }

         list.setModel(listModel);
         return true;

      } catch (UnsupportedFlavorException e) {
         return false;
      } catch (IOException e) {
         return false;
      }
   }
}

@healix:请不要尝试在评论中发布代码,因为它将保持未格式化状态,从而无法阅读。相反,请编辑您的原始问题并添加附注,然后在评论中告诉我您已经完成此操作。 - Hovercraft Full Of Eels
实际上,除非是在Java 7中更改,否则我总是获得包含'File'对象的java.util.List - 我还没有能够使泛型在这方面起作用;) - MadProgrammer
@MadProgrammer:你可能是对的。让我编辑一下我的答案。 - Hovercraft Full Of Eels
我编辑了主代码并将其放回我的transferHandler中。它就在JList实现的下面。 - rogerthat
1
@healix:你有没有看过任何关于这方面的教程?对于这种类型的行为,您不需要或使用MouseListener,并且您肯定无法猜测如何做到这一点。请参阅我的Edit 2以获取一些示例代码。 - Hovercraft Full Of Eels
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接