ドラッグアンドドロップでファイルを受け取るJavaアプリ

「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 {
				// ファイルを受け取る
				List files = (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;
		}
	}
}

実行すると、こんな画面が出てきます。

Ss 2013121619385601

のっぺらぼうです。
JTextAreaが貼られただけ。

Ss 2013121619385602

そのJTextAreaにファイルをドラッグすることで、ファイル名のリストが表示されます。

Ss 2013121619385603

Ss 2013121619385604

ドロップ操作の処理を行うクラスを作る

ドロップ操作の処理を行うクラス (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 {
				// ファイルを受け取る
				List files = (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> で受け取るあたりでちょっとハマったくらいですかね (^^;

いつでも使えそうなので、マスターしておくと重宝しそうです。

無料メールセミナー