torutkのブログ

ソフトウェア・エンジニアのブログ

SwingコンポーネントへWindows ExplorerからファイルをDrag & Drop

PDFファイルの結合・分割のツールをJavaで作成する際、SwingのJListにOSネイティブのツール(Windwosの場合はExplorer)からファイルをDrag & DropするGUIを設けようとしました。
しかし、JListやJTableはデフォルトではDropに対応していないことが判明しました。
http://java.sun.com/docs/books/tutorial/uiswing/dnd/intro.html#defaultSupport

そこで、SwingでのDrag & Dropの処理について手持ちの書籍、インターネットを探しまわってみましたが、分かりやすい説明が意外となく、ちょっと難航しました。以下その際のメモです。

インターネット捜索の旅

まず、上記URLのThe Java TutorialでSwingのDrag & DropとData Transferの仕組みを把握しました。この記事を元にしたと思われるIT Proの連載記事も多少参考になりました。
「Java SE 6完全攻略」第29回 Swingでのドラッグ&ドロップ その1 | 日経 xTECH(クロステック)
ただ、この記事の内容はサンプルコードも含めちょっと難しく、これだけでは理解が不十分でした。そこで、ちょうどJListへファイルのDropを扱った以下のブログにあるFileDropHandlerのサンプルコードと解説を読み、ようやく自分でコードを書けるようになりました。
http://weblogs.java.net/blog/shan_man/archive/2006/09/toplevel_drop_w.html

JListでファイルのドロップを扱う方法

まず、JListにドロップを扱うためのTransferHandlerサブクラスをセットします。

    DefaultListModel fileListModel = new DefaultListModel();
    JList fileList = new JList(fileListModel);
    fileList.setTransferHandler(new FileDropHandler(fileListModel));

TransferHandlerサブクラスは、今回の場合ファイルを扱います。Dropだけ扱えればよいので、canImportメソッドとimportDataメソッドをオーバーライドします。

public class FileDropHandler extends TransferHandler {
    public FileDropHandler(DefaultListModel aModel) {
        model = aModel;
    }
    public boolean canImport(TransferSupport support) {
        if (!support.isDrop()) {
            return false;
        }
        return support.isDataFlavorSupported(DataFlavor.javaFileListFlavor);
    }

    public boolean importData(TransferSupport support) {
        if (!canImport(support)) {
            return false;
        }

        Transferable transferable = support.getTransferable();

        try {
            Object data =
                transferable.getTransferData(DataFlavor.javaFileListFlavor);
            List fileList = (List)data;
            for (Object file : fileList) {
                model.addElement(file);
            }
        } catch (UnsupportedFlavorException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
                
        return true;
    }

    private DefaultListModel model;
}