OSTRACISM CO.

C#とObjective-CとJavaと...

ドラッグ&ドロップ

 GraphicGripGropは簡単なドラッグ&ドロップの例として、外部からのアイテムのドロップを実装してある。しかし、ドロップしてもアプリケーションの外観に変化を与えていないので使うだけでは気づかないと思う。本来ドラッグ&ドロップはユーザビリティの向上のための機能なので、ユーザフィードバックは必須なのだが、可能な限りサンプルはシンプルにしたいため最低限の表現としている。
 GraphicGripGropはドロップされたアイテムがファイルならばインデックスあるいは検索元ファイルとして、ディレクトリならば検索先ディレクトリとして扱う。GraphicGripGropからのドラッグはサポートしていない。

C#

this.DragDrop += new System.Windows.Forms.DragEventHandler(this.GGG4W_DragDrop);
this.DragEnter += new System.Windows.Forms.DragEventHandler(this.GGG4W_DragEnter);

private void GGG4W_DragEnter(object sender, System.Windows.Forms.DragEventArgs e) {
	e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.All : DragDropEffects.None;
}

private void GGG4W_DragDrop(object sender, System.Windows.Forms.DragEventArgs e) {
	string[] s = (string[])e.Data.GetData(DataFormats.FileDrop, false);
	foreach(string path in s) {
		if (Directory.Exists(path)) {
			m_gs.m_topDirPath = path;
		}			
		else if (File.Exists(path)) {
			if (m_gs.CheckIndexFile(path)) {
				m_gs.m_indexFilePath = path;
			}
			else {
				m_gs.m_target.m_filePath = path;
			}
		}
	}
}
 GGG4Wメインフォームのプロパティ一覧のイベントでドラッグ&ドロップ関連のコールバックの枠を作る。必須なのはGGG4W_DragEnterとGGG4W_DragDrop(これはGGG4Wクラスで普通に作ったときに自動で付けられるメソッド名)。
 メインフォームのDragDropというデリゲートにGGG4W_DragDropを追加するコードはVisual Studioによって自動で追加される。
 GGG4W_DragEnterでドラッグされてきたアイテムの種類等で許可・不許可等を返す。
 GGG4W_DragDropでドロップされたアイテム毎の処理をする。

Objective-C

[mainWindow setDelegate: self];
[mainWindow registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];

...

- (unsigned int)draggingEntered:(id)sender
{
	return NSDragOperationGeneric;
}

- (unsigned int)draggingUpdated:(id)sender
{
	return NSDragOperationGeneric;
}

- (void)draggingExited:(id)sender
{
}

- (BOOL)prepareForDragOperation:(id)sender
{
    return YES;
}

- (BOOL)performDragOperation:(id)sender
{
	NSPasteboard *pbd = [sender draggingPasteboard];
	NSArray *filePathArray = [pbd propertyListForType: NSFilenamesPboardType];
	NSFileManager *fm = [NSFileManager defaultManager];
	int i;
	BOOL isDir;
	for (i = 0; i < [filePathArray count]; i++) {
		NSString *path = [filePathArray objectAtIndex: i];
		if ([fm fileExistsAtPath: path isDirectory: &isDir] && isDir) {
			[m_gs setTopDirPath:path];
		} 
		else if ([fm fileExistsAtPath: path]) {
			if ([m_gs checkIndexFile:path])
				[m_gs setIndexFilePath:path];
			else
				[[m_gs target] setFilePath:path];
		}
	}
	return YES;
}

- (void)concludeDragOperation: (id) sender
{
}
 メインウィンドウに制御クラスのインスタンスをsetDelegateしてあることを前提として(setDelegate自体はドラッグ&ドロップに限らずそもそも必須で、コードで書かなくとも.nibでも設定できる)、メインウィンドウにregisterForDraggedTypesで対象アイテムの種類を登録する。ここでは全てのペーストボートタイプとしている。
 必要なメソッドはdraggingEntered、draggingUpdated、draggingExited、prepareForDragOperation、performDragOperation、concludeDragOperationだが、どれが省略可能かは調べていない。少なくともdraggingEnteredとdraggingUpdatedとprepareForDragOperationで適切な値を返す必要がある。  performDragOperationでドロップされたアイテム毎の処理をする。

Java

DropTargetListener dtl = new DropTargetAdapter() {
	public void drop(DropTargetDropEvent dtde) {
		dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
		List list = null;
		try {
			DataFlavor[] df = dtde.getCurrentDataFlavors();
			Transferable t = dtde.getTransferable();
			list = (List)t.getTransferData(DataFlavor.javaFileListFlavor);
			for (int i = 0; list != null && i < list.size(); i++) {
				File f = (File)list.get(i);
				if (f.isDirectory()) {
					m_gs.m_topDirPath = f.getPath();
				}
				else if (f.isFile()) {
					if (m_gs.checkIndexFile(f.getPath()))
						m_gs.m_indexFilePath = f.getPath();
					else
						m_gs.m_target.m_filePath = f.getPath();
				}
			}
		}
		catch (Exception e) {
		}
		dtde.dropComplete(true);
	}
};
this.setDropTarget(new DropTarget(this, dtl));
tblResult.setDropTarget(new DropTarget(tblResult, dtl));
btnSearch.setDropTarget(new DropTarget(btnSearch, dtl));
 メインウィンドウに、DropTargetAdapterクラスを継承したDropTargetListenerインターフェースの実装クラスのオブジェクトインスタンスをsetDropTargetで登録する。ウィンドウだけを登録してもボタン等にたまたまドロップしたときにはコールバックは呼ばれないのでボタンやテーブルにもsetDropTargetで同じオブジェクトインスタンスを登録している。他環境ではハンドラーがなければ親ウィンドウに送られるのだが、どうやらSwingはそうではないようだ。
 DropTargetAdapterクラスが省略時の動作を受け持つため、実際に実装すべきメソッドは少ない。ここではdropメソッドだけを実装している。
 dropメソッドでドロップされたアイテム毎の処理をする。

2005.09.18
「インデックス」へ戻る

OSTRACISM CO.
OSTRA / Takeshi Yoneki