トップ » 技術記事 » API で覚える Adobe AIR(5) - Adobe AIR ドラッグ&ドロップ API について

API で覚える Adobe AIR(5) - Adobe AIR ドラッグ&ドロップ API について

タグ: ActionScript Adobe AIR javascript

Adobe AIR が話題になっています。Adobe AIR を使えば、これまで使ってきた Web アプリケーションの技術、HTML/JavaScript や Flash/Flex を利用して、デスクトップアプリケーションを作ることができます。今回から、数回にわたって、Adobe AIR の API をテーマにして、AIR の各機能を紹介していきます。5回目の今回は、ドラッグ&ドロップついて見ていきます。

ドラッグ&ドロップについて

Adobe AIRでは、OSネイティブなドラッグ&ドロップをサポートしています。これを利用することで、AIRのウィンドウにファイルをドロップしたり、AIRからドラッグしたファイルをコピーしたりできます。Webアプリケーションでは、Webブラウザ内だけのドラッグ&ドロップはサポートすることはできましたが、ブラウザを超えて、デスクトップにファイルをドロップしたり、逆にデスクトップから、ファイルをブラウザにドラッグすることはできませんでした。しかし、AIRなら、OSネイティブなドラッグ&ドロップをサポートしているので、これを行うことができます。

前回、AIRでのクリップボード処理について紹介しましたが、ドラッグ&ドロップで対応している形式は、クリップボードと同じで、画像(BITMAP_FORMAT)、ファイル、テキスト、URL文字列、オブジェクトなどです。ドラッグ&ドロップの処理においても、Clipboard クラスを利用して処理を行います。

ドラッグ&ドロップ(Drag & Drop)は、その名前のごとく、「ドラッグ」(オブジェクトを掴んで動く状態にすること)と、「ドロップ」(ドラッグしたオブジェクトを落とす、ドラッグ状態を終わりにすること)の2つの動作から成り立っています。

そのため、ここでの解説も、ドラッグとドロップに分けて解説します。また、JavaScript(HTML) と ActionScript(Flex)でも、若干処理が異なりますので、注意が必要です。

AIRでドラッグ処理の実装

まずは、AIR アプリから別のアプリケーションにオブジェクトをドラッグする方法について見ていきます。

Flex (ActionScript) の場合

ドラッグを行う場合は、何をドラッグするのか、ドラッグするオブジェクトの情報を Clipboard 形式で作成し、それを、NativeDragManager.doDrag() に指定することでドラッグさせることができます。

以下は、test.jpg という画像ファイルを画面に表示しておいて、これをドラッグできるようにするにするものです。

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml">
	<mx:Image id="a_img"

		source="test.jpg"
		mouseDown="onMouseDown()"/>
<mx:Script><![CDATA[
// マウスボタンをクリックしたらドラッグを開始する
private function onMouseDown():void {
	var a_file:File = new File("app:/test.jpg");
	var cb:Clipboard = new Clipboard();
	cb.setData(ClipboardFormats.FILE_LIST_FORMAT, [a_file]);
	NativeDragManager.doDrag(a_img, cb);
}
]]></mx:Script>
</mx:WindowedApplication>

ただし、上記のプログラムで、デスクトップに画像をドラッグすると、ファイルがコピーされるのではなく、ファイルが移動してしまいます。そのため、2回目の実行では、画像がなくなってしまいます。

ドラッグをコピーモードで実行するためには、NativeDragManager に、以下のようにオプション(NativeDragOptions)をつけて実行します。

private function onMouseDown():void {
	var a_file:File = new File("app:/test.jpg");
	var cb:Clipboard = new Clipboard();
	cb.setData(ClipboardFormats.FILE_LIST_FORMAT, [a_file]);
	var opt:NativeDragOptions = new NativeDragOptions();
	opt.allowCopy = true;
	opt.allowMove = false;
	opt.allowLink = true;
	NativeDragManager.doDrag(a_img, cb, null, null, opt);
}

他に、NativeDragManager.doDrag() メソッドには、ドラッグ時のアイコンやマウスの位置などを指定することができます。

HTML(JavaScript)の場合

HTML/JavaScriptでは、はじめからオブジェクトが外部へドラッグ可能な状態になっています。そのため、JavaScript で行うべきことは、ドラッグされたタイミングで、何をドラッグしているのかという情報を設定することです。

以下は、画像ファイル「test.jpg」をデスクトップへドラッグできるようにしたプログラムです。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
    <!-- ui -->

    <img id="a_img" src="test.jpg" />
    <!-- script -->
    <script src="AIRAliases.js"></script>

    <script>
    function $(name) { return document.getElementById(name); }
    var MIME_FILE_LIST = "application/x-vnd.adobe.air.file-list";
    var a_img = $("a_img");
    // イベントを登録
    a_img.addEventListener("dragstart", onDragStart);
    // ドラッグが開始されたときにデータをセットする
    function onDragStart(event) {
        var drag_file = new air.File(a_img.src);
        event.dataTransfer.setData(MIME_FILE_LIST,[drag_file]);
        event.dataTransfer.effectAllowed = "copy";
    }
    </script>
</body></html>
画像ファイルをドラッグしてみたところ
画像ファイルをドラッグしてみたところ

AIRでドロップの処理

次に、Windows のエクスプローラーなどから、AIRアプリに画像ファイルをドロップする処理について見ていきます。

Flex(ActionScript)の場合

Flex では、MXMLのそれぞれのコントロールには、ネイティブなドラッグ&ドロップのためのイベントハンドラが用意されています。それは、「nativeDragEnter」や「nativeDragDrop」などです。

オブジェクトをAIRのウィンドウにドロップすると、次の順番でイベントが発生します。

  • (1) nativeDragEnter .. オブジェクトがドロップ対象領域に入った
  • (2) nativeDragOver .. オブジェクトがドロップ対象領域内にある
  • (3) nativeDragDrop .. オブジェクトがドロップされた
  • (4) nativeDragExit .. オブジェクトがドロップ対象領域から外れた

順序の(1)~(2)の状態にあるとき、何も処理を行わないとオブジェクトはドロップできません。つまり、順序(3)の nativeDragDrop は発生しません。そこで、nativeDragEnter イベントで、ドロップを許可してあげると(NativeDragManager.acceptDragDrop()を呼ぶ)、オブジェクトがドロップできる状態になり、ユーザーがオブジェクトをドロップした(マウスを離した)時に、nativeDragDrop イベントが発生するようになります。

以下は、Flex のプログラムですが、Windows のエクスプローラーから、画像ファイルをドロップすると、その画像を表示します。

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml">

	<mx:TextInput id="a_txt" text="ここにドロップ!"
		x="10" y="10"
		nativeDragEnter="onEnter(event)"

		nativeDragDrop="onDrop(event)"
		/>
	<mx:Image id="a_img" x="10" y="50"/>

	<mx:Script><![CDATA[
	private function onEnter(e:NativeDragEvent):void {
		var cb:Clipboard = e.clipboard;
		if (cb.hasFormat(ClipboardFormats.FILE_LIST_FORMAT)) {
			a_txt.text = "ドロップできます";
			NativeDragManager.acceptDragDrop(a_txt);
		} else {
			a_txt.text = "ファイルをドラッグしてください。";
		}
	}
	private function onDrop(e:NativeDragEvent):void {
		var cb:Clipboard = e.clipboard;
		var file_ary:Array;
		file_ary = cb.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
		a_img.source = File(file_ary[0]).url;
	}
	]]></mx:Script>
</mx:WindowedApplication>

上記のプログラムの関数 onEnter() と onDrop() は、それぞれ nativeDragEnter イベントと nativeDragDrop イベントが発生すると実行されるようになっています。これは、TextInput コントロールで指定しています。

onEnter() 関数では、オブジェクトがドロップ対象領域に入ったに実行されます。その時、引数として得られる NativeDragEvent 型のオブジェクトにある、clipboard プロパティを調べることで、ドロップ対象オブジェクトの情報を得ることができます。そして、ここでは、ドロップ対象オブジェクトがファイルリスト形式 (FILE_LIST_FORMAT)ならば、ドロップすることを許可しています。

次に、ファイルがドロップされたとき(nativeDragDropイベント)に実行される onDrop() 関数ですが、ここでは、ドロップされたファイルリスト形式のデータを取得して、Image コンポーネントでそれを表示するような処理を行っています。

HTML(JavaScript)の場合

JavaScript で同じ動作をするプログラムを作ってみます。JavaScript は、Flex と違った仕方でドラッグ&ドロップを実装します。基本的な部分(イベントを登録しておいて、オブジェクトがドロップされるのを待つ)は同じなのですが、イベントの名前や取得したデータの処理の仕方が違うのです。

JavaScript でドロップを受けるには、次のイベントをイベントリスナに登録します。

  • (1) dragenter .. オブジェクトがドロップ対象領域に入った
  • (2) dragover .. オブジェクトがドロップ対象領域にある
  • (3) drop .. オブジェクトがドロップされた
  • (4) dragleave .. オブジェクトがドロップ領域から離れた

そして、イベントハンドラでは、event 引数を取り、それに設定されているプロパティを用いてドロップに関する情報を取得します。

以下は、HTML/JavaScript で、Windows のエクスプローラーから、画像ファイルをドロップすると、その画像を表示するというプログラムです。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>

    <!-- ui -->
    <div id="a_div">ここにドラッグしてみてください。</div>
    <div id="b_div"></div>
    <!-- script -->

    <script src="AIRAliases.js"></script>
    <script>
    function $(name) { return document.getElementById(name); }
    function showProp(obj) { // プロパティを調べる関数
        for(var prop in obj) {
            air.trace(prop + "=" + obj[prop]);
        }
    }
    var a_div = $("a_div");
    var b_div = $("b_div");
    // イベントの登録
    a_div.addEventListener("dragenter", onDragOver);
    a_div.addEventListener("dragover",  onDragOver);
    a_div.addEventListener("drop",      onDrop);
    // イベントハンドラ
    function onDragOver(event) { event.preventDefault(); }
    function onDrop(event) {
        var cb = event.dataTransfer;
        // ファイルがドラッグされたか調べる
        var typeFileList = "application/x-vnd.adobe.air.file-list";
        if (cb.types.toString() == typeFileList) {
            var file_ary = cb.getData(typeFileList);
            var img = document.createElement("img");
            img.src = file_ary[0].url;
            b_div.appendChild(img);
        }
    }
    </script>

</body></html>

プログラム中の関数 onDrop() は、drop イベントが発生すると実行されます。ここでは、その引数としてえられた event.dataTransfer を調べることで、ドラッグされたオブジェクトに関する情報を得ることができます。

特に、event.dataTransfer.types を調べると、どのような種類のオブジェクトがドロップされたのかが分かります。ここで得られる種類は、MIMEタイプとして得られます。この MIMEタイプは、Flex のクリップボード形式とは互換性がないので注意が必要です。例えば、テキストをドロップした場合には、「text/plain,text/html」という値が得られます。

ドラッグ&ドロップのまとめ

クリップボードを扱う時には、Flex と JavaScript でほどんど同じプログラムになったのに対し、ドラッグ&ドロップでは、Flex と JavaScript でかなりの部分が異なっているので注意が必要です。

Flex でも JavaScript でも、OS ネイティブのファイルドラッグなどに対応しているので、さまざまな用途に使用できます。特に、ファイルのドラッグ&ドロップは頻繁に使うのではないでしょうか。本稿が参考になれば幸いです。

Series Navigation«Adobe AIRでクリップボードを操る

執筆者紹介

クジラ飛行机

クジラ飛行机

くじらはんど(http://kujirahand/)にて、日本語プログラミング言語「なでしこ」(IPA未踏ユース採択)、テキスト音楽「サクラ」(OSPオンラインソフト大賞入賞)など多くのオンラインソフトを開発。著書に「Flexプロフェッショナルガイド」「なでしこ公式バイブル」、「一週間でマスターするActionScript3.0」など。

TrackBack URL :