java.awt.dnd.DropTarget

目的
ドロップターゲットを定義し、ドロップを受け付けるようにする。

関連クラス

今回のソース
//////////////////// DragAndDrop.java ////////////////////

class DragAndDrop
{
	public static void main(String args[])
	{
		new MainWindow();
	}
}

////////////////////////////////////////////////////////////

//////////////////// MainWindow.java ////////////////////

import java.awt.*;
import java.awt.event.*;
import java.awt.dnd.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.util.List;

class MainWindow extends Frame
{
	public MainWindow()
	{
		super("Drag And Drop Test");

		// ウインドウリスナの追加
		WindowListener listener = new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				System.exit(0);
			}
		};
		addWindowListener(listener);

		// ラベルの構築
		Label lbl = new Label("Please Drop here.",Label.CENTER);

		// ドロップターゲットの定義
		DropTarget target = new DropTarget(lbl,DnDConstants.ACTION_REFERENCE,new DropTargetListener()
		{
			public void dragEnter(DropTargetDragEvent enter)
			{
			}

			public void dragOver(DropTargetDragEvent over)
			{
			}

			public void dropActionChanged(DropTargetDragEvent action)
			{
			}

			public void dragExit(DropTargetEvent exit)
			{
			}

			// ドロップされた時にコールされる
			public void drop(DropTargetDropEvent drop)
			{
				try
				{
					Transferable transfer = drop.getTransferable();
					if(transfer.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
					{
						// ドロップされたデータの取得
						drop.acceptDrop(DnDConstants.ACTION_REFERENCE);
						List file_list = (List)transfer.getTransferData(DataFlavor.javaFileListFlavor);
						for(int i=0;i<file_list.size();i++)
						{
							String file_name = file_list.get(i).toString();
							new FileInfoDialog(MainWindow.this,file_name);
						}
						drop.getDropTargetContext().dropComplete(true);
					}
				}
				catch(Exception e)
				{
					System.err.println(e);
				}
			}
		});

		add(lbl,BorderLayout.CENTER);

		setSize(150,150);
		setVisible(true);
	}
}

////////////////////////////////////////////////////////////

//////////////////// FileInfoDialog.java ////////////////////

import java.awt.*;
import java.awt.event.*;
import java.io.File;

class FileInfoDialog extends Dialog
{
	public FileInfoDialog(Frame frame,String file_path)
	{
		super(frame,"File Information Dialog");

		// ウインドウリスナの追加
		WindowListener listener = new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				setVisible(false);
			}
		};
		addWindowListener(listener);

		// ファイル情報の取得
		File file = new File(file_path);
		String file_name = file.getName();
		long size = file.length();

		// ボタンの構築
		Button quit_button = new Button("OK");
		ActionListener listener_quit_button = new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				setVisible(false);
			}
		};
		quit_button.addActionListener(listener_quit_button);

		// 中央パネルの定義
		Panel center = new Panel();
		center.setLayout(new GridLayout(3,2));
		Label lbl_file_type = new Label("File Type",Label.CENTER);
		Label lbl_file_type_value;
		if(file.isDirectory())
		{
			lbl_file_type_value = new Label("Directory",Label.CENTER);
		}
		else
		{
			lbl_file_type_value = new Label("File",Label.CENTER);
		}
		Label lbl_file_name = new Label("File Name",Label.CENTER);
		Label lbl_file_name_value = new Label(file_name,Label.CENTER);
		Label lbl_file_size = new Label("File Size",Label.CENTER);
		Label lbl_file_size_value = new Label(new Long(size).toString() + "Byte",Label.CENTER);


		// 中央パネルへラベルの追加
		center.add(lbl_file_type);
		center.add(lbl_file_type_value);
		center.add(lbl_file_name);
		center.add(lbl_file_name_value);
		center.add(lbl_file_size);
		center.add(lbl_file_size_value);

		// 下パネルの定義
		Panel south = new Panel();
		south.add(quit_button);
		south.setBackground(Color.white);

		// パネルをダイアログへ追加
		add(center,BorderLayout.CENTER);
		add(south,BorderLayout.SOUTH);

		// ダイアログの表示
		setSize(240,120);
		setVisible(true);
	}
}

////////////////////////////////////////////////////////////
Source is here. (ZIP Format,2042Byte,Shift-JIS)

コンパイル&実行
javac DragAndDrop.java
java DragAndDrop

説明
(概略)

Java2で機能が拡張された、ドラッグアンドドロップについて、
ドロップを受け付ける機能を有するウインドウを作ってみました。

ドロップを受け付けるには、
コンポーネント(WindowやLabelなど)にドロップターゲットを設定するか、
ドロップターゲットに、コンポーネントを設定するか
という2通りの方法があります。
今回採用したのは、後者の方です。

ドラッグソース(ドロップされるオブジェクト)のデータを受け取る辺りは、
ちょっと複雑ですけど、ドロップに反応するには、
DropTargetListener中のdropメソッドを定義するだけなので、
意外と簡単に出来ますね。
他の、dropExitやdropEnterメソッドも、必要に応じて使うと良いでしょう。

Swingで、JavaのGUIは、WindowsのGUIに追いついて来た
と言われていますが、このドラッグアンドドロップ機能辺りをみても、
本当にそういう感じがしますね。
出来れば、実行速度が速くなると、実用性も増すんですけどね。

(サンプルプログラムの説明)

java.util.List
代わり映えのしないコードに見えますが、
実は、Listというのは、java.awt.Listとjava.util.List
の二つがあって、名前が重なってしまっているんですね。
なので、明示的にjava.util.Listと宣言しなくてはならないのです。
new DropTargetListener()
ここでは、DropTargetListenerを構築するのに、
内部クラスを用いています。
わざわざ新しいクラスを作らなくても良いようにするためだとか。
(どっかの雑誌に書いてあったけど、本当かな〜?)
よく、WindowAdapterとかでも使いますよね。
だから、ちょっと真似して使ってみました(笑)。

分かりにくいかも知れませんけど、
内部クラスで構築している、DropTargetListenerインターフェースは、
DropTargetクラスの3番目の引数となっています。
transfer.isDataFlavorSupported(DataFlavor.javaFileListFlavor)
DataFlavor.javaFileListFlavorというのは、
Windowsのエクスプローラのような、ファイルリストのような
ドラッグソース(ドラッグされるオブジェクト)を指すようです。
(やっぱりちゃんと分かってない(^^;)
つまり、それ以外は無視するようになっています。
List file_list = (List)transfer.getTransferData(DataFlavor.javaFileListFlavor);
DataFlavor.javaFileListFlavorという種類のオブジェクトでは、
List型が返ってくるようになっているので、
List型でキャストして受けています。

ちなみに、Listインターフェースは、JDK1.2から導入されたもので、
コレクションフレームワークの一部です。
コレクションとは、簡単に言えば、オブジェクトの集まりで、
その集まりから、要素を取り出したり、整列したりする操作を定義したものが、
コレクションフレームワークと言えるでしょう。
java.util.Arrays.sortメソッドなどは、この恩恵にあずかってます。
drop.getDropTargetContext().dropComplete(true);
ドロップ操作を終了させるメソッドです。
私は、Windows95上で確認しているのですが、
このメソッドを呼び出さないと、ドラッグソースを提供する
エクスプローラが、ロックされてしまい、使えなくなってしまうんです。
だから、きちんとドロップの終了を知らせるようにしましょう。