简体   繁体   English

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

[英]How can I use Drag-and-Drop in Swing to get file path?

I have a JTextField in my Swing application that holds the file path of a file selected to be used.我的Swing应用程序中有一个JTextField ,用于保存选择使用的文件的文件路径。 Currently I have a JFileChooser that is used to populate this value.目前我有一个用于填充此值的JFileChooser However, I would like to add the ability for a user to drag-and-drop a file onto this JTextField and have it place the file path of that file into the JTextField instead of always having using the JFileChooser .但是,我想为用户添加将文件拖放到此JTextField上的功能,并将该文件的文件路径放入JTextField而不是始终使用JFileChooser

How can this be done?如何才能做到这一点?

In case you don't want to spend too much time researching this relatively complex subject, and you're on Java 7 or later, here's a quick example of how to accept dropped files with a JTextArea as a drop target:如果您不想花太多时间研究这个相对复杂的主题,并且您使用的是 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
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
});

First you should look into Swing DragDrop support .首先,您应该查看Swing DragDrop 支持 After that there are few little tricks for different operating systems.之后,针对不同操作系统的一些小技巧。 Once you've got things going you'll be handling the drop() callback.一旦事情进展顺利,您将处理 drop() 回调。 In this callback you'll want to check the DataFlavor of the Transferable.在此回调中,您需要检查 Transferable 的 DataFlavor。

For Windows you can just check the DataFlavor.isFlavorJavaFileListType() and then get your data like this对于 Windows,您只需检查DataFlavor.isFlavorJavaFileListType()然后像这样获取数据

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

For Linux (and probably Solaris) the DataFlavor is a little trickier.对于 Linux(可能还有 Solaris),DataFlavor 有点棘手。 You'll need to make your own DataFlavor and the Transferable type will be different您需要制作自己的 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
       ....
    }
}

There is an example program which contains a class which can be used for facilitating drag and drop for files and folders:有一个示例程序,其中包含一个类,可用于促进文件和文件夹的拖放:

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

I tested this with both Windows 7 and Ubuntu 10.10, and it appears to work well in both environments.我在 Windows 7 和 Ubuntu 10.10 上对此进行了测试,它似乎在两种环境中都运行良好。

To use it, you add something like this to your code:要使用它,您可以在代码中添加如下内容:

  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

I know this is an old question but the current answers are all a bit outdated:我知道这是一个老问题,但目前的答案都有些过时:

  • since JDK 1.6 the class 'TransferHandler' should be used with new (overwritten) methods从 JDK 1.6 开始,类“TransferHandler”应该与新的(覆盖的)方法一起使用
  • support for Linux became a lot better, no need for custom handling对 Linux 的支持变得更好,无需自定义处理

This works on Linux (KDE5) and Windows 7:这适用于 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;
    }
}

Use it on any component with在任何组件上使用它

myComponent.setTransferHandler(new FileDropHandler());

This works for me.这对我有用。 I am using it like this (scala):我像这样使用它(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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM