java - 当调用 TransferHandler canImport 方法时,来自 jvm 外部的可传输数据的传输数据默认为 null 吗?

标签 java swing drag-and-drop osx-mountain-lion jlist

我正在研究 JList 组件的拖放支持,并且我希望能够支持从文件浏览器拖入的文件。然而,我只想允许拖入文件而不是文件夹。因此我尝试在我的 TransferHandler 中检查它,如下所示:

@Override
public boolean canImport(TransferSupport support) {

    if (support.getComponent().equals(this.resourceFileList)) {

        if (!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
            return false;
        } else {

            try {

                // get file list
                Transferable transferable = support.getTransferable();
                Object transferData = transferable.getTransferData(DataFlavor.javaFileListFlavor);

                // check for folders
                boolean containsFiles = false;
                List files = (List) transferData;
                for (int i = 0; i < files.size(); i++) {
                    File file = (File) files.get(i);
                    if (!file.isDirectory()) {
                        containsFiles = true;
                    }
                }

                // return file indicator
                return containsFiles;

            } catch (IOException | UnsupportedFlavorException e) {
                System.out.println("Unable to check for folders due to the following exception:\n" + e);
                return false;
            }
        }
    } else {
        return false;
    }
}

不幸的是transferData在这里似乎为空。然而,这并不是在调用 TransferHandler 的 importData 方法时发生的。有谁知道这是否是某种错误或期望的行为?

我使用的是 Mac (OSX 10.8),如果有影响的话,Java 版本是 1.7.0_21。

提前致谢!

编辑:

这是一个简短的 SSCCE,供任何人测试。只需将文件拖到列表中即可观看控制台。

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.util.List;

import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.TransferHandler;
import javax.swing.TransferHandler.TransferSupport;

public class DNDIssue extends TransferHandler {

    @Override
    public boolean canImport(TransferSupport support) {

        if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {

            try {

                Transferable transferable = support.getTransferable();
                Object transferData = transferable.getTransferData(DataFlavor.javaFileListFlavor); // <-- this returns null
                System.out.println(transferData); // null

            } catch (IOException | UnsupportedFlavorException e) {
                System.out.println("Unable to check for folders due to the following exception:\n" + e);
            } finally {
                return false;
            }
        } else {
            return false;
        }
    }

    public static void main(String[] args) {

        // create window
        JFrame window = new JFrame("DNDIssue");
        window.setSize(640, 480);
        window.setLocation(100, 100);

        // create list with model and set transfer handler
        JList<File> list = new JList<File>(new DefaultListModel<File>());
        list.setTransferHandler(new DNDIssue());

        // add enclosing scroll pane and display window
        window.getContentPane().add(new JScrollPane(list));
        window.setVisible(true);
    }
}

最佳答案

  • 我在 Windows 7 64 位上使用 JDK 1.7.0_21,您的 SSCCE 工作正常。

  • 您可以尝试以下代码吗?

      Transferable transferable = support.getTransferable();
    
      System.out.println("----");
      String mt = DataFlavor.javaFileListFlavor.getMimeType();
      for(DataFlavor df: transferable.getTransferDataFlavors()) {
        System.out.println(df.getMimeType());
        System.out.println("  "+df.getMimeType().equals(mt));
      }
    
  • SSCCE 1.0:删除

  • SSCCE 1.1:覆盖 TransferHandler#importData(...) 版本

    • InvalidDnDOperationException:无下降电流

        java.awt.dnd.InvalidDnDOperationException: No drop current
            at sun.awt.dnd.SunDropTargetContextPeer.getTransferData(SunDropTargetContextPeer.java:245)
            at sun.awt.datatransfer.TransferableProxy.getTransferData(TransferableProxy.java:73)
            at java.awt.dnd.DropTargetContext$TransferableProxy.getTransferData(DropTargetContext.java:376)
            at FileTransferHandler.canImport(DNDIssueTest.java:64)
      
    • 该问题可能与 Bug ID 6759788 https://bugs.java.com/bugdatabase/view_bug?bug_id=6759788 有关

  • SSCCE 1.2:忽略InvalidDnDOperationException

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.io.*;
import java.util.List;
import javax.swing.*;
import javax.swing.TransferHandler;
import javax.swing.TransferHandler.TransferSupport;

public class DNDIssueTest {
  public JComponent makeUI() {
    // create list with model and set transfer handler
    JList<File> list = new JList<File>(new DefaultListModel<File>());
    list.setDropMode(DropMode.INSERT);
    list.setTransferHandler(new FileTransferHandler());
    return new JScrollPane(list);
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new DNDIssueTest().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}

class FileTransferHandler extends TransferHandler {
  private static final boolean DEBUG = true;
  @SuppressWarnings("unchecked")
  @Override public boolean importData(TransferSupport support) {
    try {
      List files = (List)support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
      System.out.println("importData");
      if(!hasDirectory(files) && canImport(support)) {
        JList list = (JList)support.getComponent();
        DefaultListModel model = (DefaultListModel)list.getModel();
        for(Object o: files) {
          model.addElement(o);
        }
        return true;
      }
    } catch(Exception ex) {
      ex.printStackTrace();
    }
    return false;
  }
  private boolean hasDirectory(List list) {
    System.out.println("hasDirectory check");
    for (Object o: list) {
      if(o instanceof File) {
        File file = (File) o;
        if (file.isDirectory()) {
          return true;
        }
      }
    }
    return false;
  }
  @Override public boolean canImport(TransferSupport support) {
    if(!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
      return false;
    }
    if(!DEBUG) return true;

    Transferable transferable = support.getTransferable();
    try {
      Object transferData = transferable.getTransferData(DataFlavor.javaFileListFlavor);
      //System.out.println(transferData); // null
      System.out.println("canImport");
      return !hasDirectory((List)transferData);
    } catch (Exception e) {
      //e.printStackTrace();
      System.out.println("*** Ignore InvalidDnDOperationException ***");
      return true;
    }
  }
}
  • SSCCE 2.0:DropTargetListener 版本
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.event.*;
import java.io.*;
import java.util.List;
import javax.swing.*;

public class DNDIssueTest2 {
  public JComponent makeUI() {
    final DefaultListModel<File> model = new DefaultListModel<>();
    JList<File> list = new JList<File>(model);
    DropTargetListener dtl = new DropTargetAdapter() {
      @Override public void dragOver(DropTargetDragEvent dtde) {
        if(dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
          Transferable transferable = dtde.getTransferable();
          Object transferData = null;
          try {
            transferData = transferable.getTransferData(DataFlavor.javaFileListFlavor);
          } catch(Exception ex) {
            dtde.rejectDrag();
            return;
          }
          List<File> files = (List<File>)transferData;
          for (int i = 0; i < files.size(); i++) {
            File file = (File) files.get(i);
            if (file.isDirectory()) {
              dtde.rejectDrag();
              return;
            }
          }
          dtde.acceptDrag(DnDConstants.ACTION_COPY);
          return;
        }
        dtde.rejectDrag();
      }
      @Override public void drop(DropTargetDropEvent dtde) {
        try {
          if(dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
            dtde.acceptDrop(DnDConstants.ACTION_COPY);
            Transferable transferable = dtde.getTransferable();
            List list = (List)transferable.getTransferData(DataFlavor.javaFileListFlavor);
            for(Object o: list) {
              if(o instanceof File) {
                File file = (File) o;
                model.addElement(file);
              }
            }
            dtde.dropComplete(true);
            return;
          }
        } catch(UnsupportedFlavorException ufe) {
          ufe.printStackTrace();
        } catch(IOException ioe) {
          ioe.printStackTrace();
        }
        dtde.rejectDrop();
      }
    };
    new DropTarget(list, DnDConstants.ACTION_COPY, dtl, true);
    return new JScrollPane(list);
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new DNDIssueTest2().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}

关于java - 当调用 TransferHandler canImport 方法时,来自 jvm 外部的可传输数据的传输数据默认为 null 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16592166/

相关文章:

java - 登录网页具有隐藏 token ,该 token 在提交表单时以 POST 形式发送。如何在 Java HttpPost 中使用 token ?

java - Sun Application Server 中的 EJB 依赖项版本冲突

java - 使用 e.getsource 打开一个新窗口(JFrame)

jquery - 在 Jquery 中使新的 Div 可拖动

javascript - 拖放 Google map 标记

java - ListView中每行的颜色不同,我也想拖动该行,并且每行的背景颜色也要交换。怎么做

java - 在java中获取解压缩文件的进度

java - 如何确定 JTextfield 的整数值?

java - 问卷 GUI(我的第一个 GUI)跳过了我的问题?

Java Swing 和线程 hibernate