Java 如何在 Swing 中使用拖放来获取文件路径?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/811248/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I use Drag-and-Drop in Swing to get file path?
提问by Ascalonian
I have a JTextField in my swing application that holds the file path of a file selected to be used. Currently I have a JFileChooser that is used to populate this value. 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.
我的 Swing 应用程序中有一个 JTextField,用于保存选择使用的文件的文件路径。目前我有一个用于填充此值的 JFileChooser。但是,我想为用户添加将文件拖放到此 JTextField 上的功能,并将该文件的文件路径放入 JTextField 中,而不是始终使用 JFileChooser。
How can this be done?
如何才能做到这一点?
采纳答案by basszero
First you should look into Swing DragDrop support. After that there are few little tricks for different operating systems. Once you've got things going you'll be handling the drop() callback. In this callback you'll want to check the DataFlavor of the Transferable.
首先,您应该查看Swing DragDrop 支持。之后,针对不同操作系统的一些小技巧。一旦事情进展顺利,您将处理 drop() 回调。在此回调中,您需要检查 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. You'll need to make your own DataFlavor and the Transferable type will be different
对于 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
....
}
}
回答by hotzen
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
}
}
回答by Mr Ed
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
回答by rustyx
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 或更高版本,这里有一个快速示例,说明如何接受以 aJTextArea
作为放置目标的已放置文件:
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();
}
}
});
回答by ABika
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
- support for Linux became a lot better, no need for custom handling
- 从 JDK 1.6 开始,类“TransferHandler”应该与新的(覆盖的)方法一起使用
- 对 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());