如何在 Swing 中使用拖放来获取文件路径?

问题描述 投票:0回答:5

我的

Swing
应用程序中有一个 JTextField,它保存选择要使用的文件的文件路径。目前我有一个
JFileChooser
用于填充该值。但是,我想添加用户将文件拖放到此
JTextField
上的功能,并让它将该文件的文件路径放入
JTextField
中,而不是始终使用
JFileChooser

这怎么办?

java swing drag-and-drop
5个回答
51
投票

如果您不想花太多时间研究这个相对复杂的主题,并且您使用的是 Java 7 或更高版本,这里有一个快速示例,说明如何使用

JTextArea
作为放置目标来接受放置的文件:

JTextArea myPanel = new JTextArea();
myPanel.setDropTarget(new DropTarget() {
    public synchronized void drop(DropTargetDropEvent evt) {
        try {
            evt.acceptDrop(DnDConstants.ACTION_COPY);
            List<File> droppedFiles = (List<File>)
                evt.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
            for (File file : droppedFiles) {
                // process files
            }
            evt.dropComplete(true);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
});

45
投票

首先您应该查看Swing DragDrop 支持。之后还有一些针对不同操作系统的小技巧。一旦事情进展顺利,您将处理 drop() 回调。在此回调中,您需要检查 Transferable 的 DataFlavor。

对于 Windows,您只需检查 DataFlavor.isFlavorJavaFileListType(),然后像这样获取数据

List<File> dropppedFiles = (List<File>)transferable.getTransferData(DataFlavor.javaFileListFlavor)

对于 Linux(可能还有 Solaris),DataFlavor 有点棘手。您需要制作自己的 DataFlavor 并且 Transferable 类型会有所不同

nixFileDataFlavor = new DataFlavor("text/uri-list;class=java.lang.String");
String data = (String)transferable.getTransferData(nixFileDataFlavor);
for(StringTokenizer st = new StringTokenizer(data, "\r\n"); st.hasMoreTokens();)
{
    String token = st.nextToken().trim();
    if(token.startsWith("#") || token.isEmpty())
    {
         // comment line, by RFC 2483
         continue;
    }
    try
    {
         File file = new File(new URI(token))
         // store this somewhere
    }
    catch(...)
    {
       // do something good
       ....
    }
}

34
投票

有一个示例程序,其中包含一个可用于促进文件和文件夹拖放的类:

http://www.iharder.net/current/java/filedrop/

我在 Windows 7 和 Ubuntu 10.10 上对此进行了测试,它似乎在这两种环境中都运行良好。

要使用它,您可以在代码中添加如下内容:

  JPanel  myPanel = new JPanel();
  new  FileDrop( myPanel, new FileDrop.Listener()
  {   public void  filesDropped( java.io.File[] files )
      {   
          // handle file drop
          ...
      }   // end filesDropped
  }); // end FileDrop.Listener

23
投票

我知道这是一个老问题,但当前的答案都有点过时了:

  • 从 JDK 1.6 开始,“TransferHandler”类应该与新的(覆盖的)方法一起使用
  • 对 Linux 的支持变得更好,无需自定义处理

这适用于 Linux (KDE5) 和 Windows 7:

final class FileDropHandler extends TransferHandler {
    @Override
    public boolean canImport(TransferHandler.TransferSupport support) {
        for (DataFlavor flavor : support.getDataFlavors()) {
            if (flavor.isFlavorJavaFileListType()) {
                return true;
            }
        }
        return false;
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean importData(TransferHandler.TransferSupport support) {
        if (!this.canImport(support))
            return false;

        List<File> files;
        try {
            files = (List<File>) support.getTransferable()
                    .getTransferData(DataFlavor.javaFileListFlavor);
        } catch (UnsupportedFlavorException | IOException ex) {
            // should never happen (or JDK is buggy)
            return false;
        }

        for (File file: files) {
            // do something...
        }
        return true;
    }
}

在任何组件上使用它

myComponent.setTransferHandler(new FileDropHandler());

-5
投票

这对我有用。我像这样使用它(scala):

def onDrop(files: List[java.io.File]): Unit = { ... }

    val lblDrop = new Label {
      peer.setTransferHandler(new FileDropHandler(onDrop))
      border = EtchedBorder
    }



class FileDropHandler(val onDrop: List[java.io.File] => Unit) extends javax.swing.TransferHandler {
      import javax.swing.JComponent
      import java.awt.datatransfer.{Transferable, DataFlavor}
        import java.net.URI
    import java.io.File

    val stdFileListFlavor = DataFlavor.javaFileListFlavor
    val nixFileListFlavor = new DataFlavor("text/uri-list;class=java.lang.String")

    override def canImport(comp: JComponent, flavors: Array[DataFlavor]): Boolean =
        flavors.exists(flavor =>
            (flavor == stdFileListFlavor) ||
            (flavor == nixFileListFlavor)
        )

    override def importData(comp: JComponent, t: Transferable): Boolean = {

        val flavors = t.getTransferDataFlavors()

        val files = if (flavors.exists(_ == stdFileListFlavor)) {
            val data = t.getTransferData(stdFileListFlavor)
            importStdFileList( data )
        } else if (flavors.exists(_ == nixFileListFlavor)) {
            val data = t.getTransferData(nixFileListFlavor)
            importNixFileList( data )
        } else List()

        onDrop( files )

        !files.isEmpty
    }

    private def importStdFileList(data: Any): List[File] = {
      data.asInstanceOf[List[File]] //XXX NOT TESTED
    }

    private def importNixFileList(data: Any): List[File] = {

        def clean(rawLine: String): Option[String] = {
            val line = rawLine.trim
            if   (line.length == 0 || line == "#") None
            else                                   Some(line)
        }

        def asURI(line: String): Option[URI] = {
            try   { Some(new URI(line)) }
            catch { case e:Exception => println(e); None }
        }

        def asFile(uri: URI): Option[File] = {
            try   { Some(new File(uri)) }
            catch { case e:Exception => println(e); None }
        }

        data.asInstanceOf[java.lang.String].split("\n")
     .toList flatMap clean flatMap asURI flatMap asFile
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.