有人知道JDK1.6和JDK1.7之间的拖放行为差异吗?当我将URL从浏览器拖放到需要支持JDK1.5、JDK1.6和JDK1.7的应用程序时,我遇到了一个不同之处(如下所示)。我现在想知道是否存在其他差异以及它们是否有文档记录。
我遇到的不同行为是,当通过单击并拖动URL将其从浏览器(而不是地址栏)拖放到Java应用程序上时。在JDK1.6上,Transferable不支持DataFlavor.javaFileListFlavor,而在JDK1.7上支持(尽管在请求其传输数据时会得到空列表)。以下代码说明了问题。它打开一个JFrame,您可以在其中拖放像http://www.google.com这样的URL,并打印出它使用的是文件列表味还是URI列表味。
我可以轻易地为此问题创建一个解决方法,但我更感兴趣的是任何更多关于这些差异和/或文档方面的了解。 编辑 进一步的调查/搜索使我认为JDK7上的行为是创建URI和文件列表数据格式并在可传输对象中同时提供它们。然后,文件列表仅包含表示文件的URI。因此,当仅拖放URL时,文件列表为空。我无法在JDK源代码中找到这个问题,因为似乎可传输对象/传输数据是在本地代码(或至少我找不到源代码的代码)中创建的。OpenJDK邮件列表上有一个讨论类似问题,其中包含以下引用:
我遇到的不同行为是,当通过单击并拖动URL将其从浏览器(而不是地址栏)拖放到Java应用程序上时。在JDK1.6上,Transferable不支持DataFlavor.javaFileListFlavor,而在JDK1.7上支持(尽管在请求其传输数据时会得到空列表)。以下代码说明了问题。它打开一个JFrame,您可以在其中拖放像http://www.google.com这样的URL,并打印出它使用的是文件列表味还是URI列表味。
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.TransferHandler;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class DragAndDropTester {
private static DataFlavor URI_LIST_FLAVOR = null;
static {
try {
URI_LIST_FLAVOR = new DataFlavor( "text/uri-list;class=java.lang.String" );
}
catch ( ClassNotFoundException ignore ) {
}
}
public static void main( String[] args ) {
try {
EventQueue.invokeAndWait( new Runnable() {
public void run() {
JFrame testFrame = new JFrame( "Test" );
JPanel contents = new JPanel( new BorderLayout() );
contents.add( new JLabel( "TestLabel" ), BorderLayout.CENTER );
contents.setTransferHandler( createTransferHandler() );
testFrame.getContentPane().add( contents );
testFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
testFrame.setSize( 200, 200 );
testFrame.setVisible( true );
}
} );
} catch ( InterruptedException e ) {
throw new RuntimeException( e );
} catch ( InvocationTargetException e ) {
throw new RuntimeException( e );
}
}
private static TransferHandler createTransferHandler(){
return new TransferHandler( ){
@Override
public boolean importData( JComponent comp, Transferable aTransferable ) {
try {
if ( aTransferable.isDataFlavorSupported( DataFlavor.javaFileListFlavor ) ) {
System.out.println("File list flavor");
List<File> file_list = ( List<File> ) aTransferable.getTransferData( DataFlavor.javaFileListFlavor );
System.out.println( "file_list = " + file_list );
}
if ( URI_LIST_FLAVOR != null && aTransferable.isDataFlavorSupported( URI_LIST_FLAVOR ) ){
System.out.println("URI list flavor");
String uri_list = ( String ) aTransferable.getTransferData( URI_LIST_FLAVOR );
System.out.println( "uri_list = " + uri_list );
}
} catch ( UnsupportedFlavorException e ) {
throw new RuntimeException( e );
} catch ( IOException e ) {
throw new RuntimeException( e );
}
return true;
}
@Override
public boolean canImport( JComponent comp, DataFlavor[] transferFlavors ) {
return true;
}
};
}
}
在JDK 1.7.01上的输出结果
File list flavor
file_list = []
URI list flavor
uri_list = http://www.google.com
JDK1.6.0.18的结果输出
URI list flavor
uri_list = http://www.google.com
我可以轻易地为此问题创建一个解决方法,但我更感兴趣的是任何更多关于这些差异和/或文档方面的了解。 编辑 进一步的调查/搜索使我认为JDK7上的行为是创建URI和文件列表数据格式并在可传输对象中同时提供它们。然后,文件列表仅包含表示文件的URI。因此,当仅拖放URL时,文件列表为空。我无法在JDK源代码中找到这个问题,因为似乎可传输对象/传输数据是在本地代码(或至少我找不到源代码的代码)中创建的。OpenJDK邮件列表上有一个讨论类似问题,其中包含以下引用:
编辑2如果您从本地拖动文件列表到Java中,则应用程序会看到URI列表和文件列表。如果您拖入URI列表,则它会看到URI列表,如果所有URI都是文件,则还会看到非空文件列表,否则只会看到空文件列表。
根据serg.nechaev的回答,我在32/64位Linux系统和几个Windows系统上进行了更多的测试(从XP到Windows7)。在JDK7上的Linux上,我总是得到URI数据格式,加上一个空文件列表数据格式。在Windows上,我得到了一个URI数据格式和一个非空的文件列表数据格式。似乎在临时目录中创建了一个.URL文件,并将其作为文件列表数据格式传递,而这在JDK 6中不是这种情况。
在所有这些情况下的解决方案是首先检查URI数据格式,然后使用文件列表数据格式作为备用。