「Explore (Windows)やFinder (Mac)からドラッグアンドドロップでファイルを受け取る」という操作ができると便利ですよね。
これはTransferHandlerというクラスを使って実装できます。
ドラッグアンドドロップでファイルを受け取る
早速コードを見てみましょう。
前半は起動のためのコードや、GUIを作るためのコードなので飛ばし読みしてください。
大切なのは59行目からです。
package jp.beourselves.open.sample.dropfiles; 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.util.List; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.TransferHandler; public class DropAndListFileName { private JFrame frame; private JTextArea textArea; /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { DropAndListFileName window = new DropAndListFileName(); window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the application. */ public DropAndListFileName() { initialize(); } /** * Initialize the contents of the frame. */ private void initialize() { frame = new JFrame(); frame.setBounds(100, 100, 450, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JScrollPane scrollPane = new JScrollPane(); frame.getContentPane().add(scrollPane, BorderLayout.CENTER); textArea = new JTextArea(); scrollPane.setViewportView(textArea); // ドロップ操作を有効にする textArea.setTransferHandler(new DropFileHandler()); } /** * ドロップ操作の処理を行うクラス */ private class DropFileHandler extends TransferHandler { /** * ドロップされたものを受け取るか判断 (ファイルのときだけ受け取る) */ @Override public boolean canImport(TransferSupport support) { if (!support.isDrop()) { // ドロップ操作でない場合は受け取らない return false; } if (!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { // ドロップされたのがファイルでない場合は受け取らない return false; } return true; } /** * ドロップされたファイルを受け取る */ @Override public boolean importData(TransferSupport support) { // 受け取っていいものか確認する if (!canImport(support)) { return false; } // ドロップ処理 Transferable t = support.getTransferable(); try { // ファイルを受け取る Listfiles = (List ) t.getTransferData(DataFlavor.javaFileListFlavor); // テキストエリアに表示するファイル名リストを作成する StringBuffer fileList = new StringBuffer(); for (File file : files){ fileList.append(file.getName()); fileList.append("\n"); } // テキストエリアにファイル名のリストを表示する textArea.setText(fileList.toString()); } catch (UnsupportedFlavorException | IOException e) { e.printStackTrace(); } return true; } } }
実行すると、こんな画面が出てきます。
のっぺらぼうです。
JTextAreaが貼られただけ。
そのJTextAreaにファイルをドラッグすることで、ファイル名のリストが表示されます。
ドロップ操作の処理を行うクラスを作る
ドロップ操作の処理を行うクラス (DropFileHandler)を63行目から作っています。
このクラスはTransferHandlerクラスを継承し、次の2つのメソッドをオーバライドしています。
- canImport(TransferSupport support)
- importData(TransferSupport support)
canImport(TransferSupport support)メソッド
まずはcanImport(TransferSupport support)メソッド。
同名のメソッドが2つありますが、TransferHandler.TransferSupportクラスを引数とするメソッドを使うことが奨励されています。
このメソッドでは、ファイルなどがドラッグアンドドロップされてきたときに、受け取っていいものかを判定します。
68〜84行目を見てください。
/** * ドロップされたものを受け取るか判断 (ファイルのときだけ受け取る) */ @Override public boolean canImport(TransferSupport support) { if (!support.isDrop()) { // ドロップ操作でない場合は受け取らない return false; } if (!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { // ドロップされたのがファイルでない場合は受け取らない return false; } return true; }
ここでは2つの判定をしています。
- ドロップ操作か
- ドロップされたのは「ファイル」か
ドロップ操作か
TransferHandler.TransferSupportクラスのisDrop()メソッドを使うことで、ドロップ操作が行われたかを確認できます。
ドロップされたのは「ファイル」か
ドロップされているのがファイルかどうかは、TransferHandler.TransferSupportクラスのisDataFlavorSupported()メソッドで確認できます。
DataFlavor.javaFileListFlavorで「ファイル」かどうかの判定をします。
どちらも問題なければ、canImportはtrueを返すようになっています。
importData(TransferSupport support)メソッド
続いてimportData()メソッドです。
こちらも同名のメソッドが2つありますが、TransferHandler.TransferSupportクラスを引数とするメソッドを使うことが奨励されています。
このメソッドで実際にデータを受け取っています。
86〜115行目を見てください。
/** * ドロップされたファイルを受け取る */ @Override public boolean importData(TransferSupport support) { // 受け取っていいものか確認する if (!canImport(support)) { return false; } // ドロップ処理 Transferable t = support.getTransferable(); try { // ファイルを受け取る Listfiles = (List ) t.getTransferData(DataFlavor.javaFileListFlavor); // テキストエリアに表示するファイル名リストを作成する StringBuffer fileList = new StringBuffer(); for (File file : files){ fileList.append(file.getName()); fileList.append("\n"); } // テキストエリアにファイル名のリストを表示する textArea.setText(fileList.toString()); } catch (UnsupportedFlavorException | IOException e) { e.printStackTrace(); } return true; }
まずは先に紹介したcamImport()を使って、受け取っていいものか確認しています (91〜94行目)。
受け取っていいものであれば、受け取ります (96〜113行目)。
この際、ファイルは List<File> として受け取るというところがミソです (100行目)。
102〜110行目では、受け取ったファイルのファイル名を取得し、テキストエリアに貼り付けています。
setTransferHandler()でセットする
以上の処理を実装したDropFileHandlerクラスを、60行目でJTextAreaにセットしています。
// ドロップ操作を有効にする textArea.setTransferHandler(new DropFileHandler());
これで、JTextAreaにファイルをドロップしたら、DropFileHandlerの処理が発動して、ファイルを受け取ってくれるようになります。
おわりに
ファイルをドラッグアンドドロップで受け取るというのは、アプリとしては今や普通の操作になっていますよね。
最初この処理を書こうと思った時、面倒くさそうだと思ったのですが、やってみたらそれほど難しくなかったです。
ファイルを List<File> で受け取るあたりでちょっとハマったくらいですかね (^^;
いつでも使えそうなので、マスターしておくと重宝しそうです。
元大手電機メーカのシステムエンジニア。
詳しくはこのサイトについての「サイト管理者について」をご覧ください。