今回から数回に分け、ドラッグ&ドロップにおけるSend処理を紹介します。ウィンドウ上のオブジェクト(画像、テキスト、ファイル情報など)をドラッグし、Finderなどの別アプリケーションにドロップする仕組みを解説します。
Receve処理とは異なり、Send処理ではデータを受け渡し用ルーチンを「コールバックルーチン」として実装しておく必要はありません。ドラッグしたいデータの表示範囲でマウスクリックが発生した時点で、逐次必要な処理を実行していく形となります。ただし、少々特別なケースに対応するため、データ受け渡し用コールバックルーチンを用いる場合もありますが、それについては別の機会に詳しく解説したいと思います。また残念ながら、本サンプルアプリケーションにはSend処理は実装されていませんので、これから紹介するルーチンは「仮想的な処理」に対するサンプルソースコードとなります。ご了承ください。
先ほど、ドロップするターゲットとして「Finderなどの別アプリケーション」と記述しましたが、当然ターゲットは自分自身でもかまいません。例えば、あるオブジェクトを同じウィンドウや別ウィンドウ内の特定の場所へ移動したりする場合などです。Finderであれば、アイコンをドラッグ&ドロップで別のフォルダへ移動、複製する処理に相当します。結局、Send処理のターゲットとしては以下の3種類を念頭に置けばよいでしょう。当然、Finderも別アプリケーションのひとつなのですが(笑)、システムと密接に関係しているということで、今回はあえて区別をしてみました。
(1)自分自身(Send処理をしているアプリケーション)
(2)別アプリケーション(Adobe Photoshopなど...)
(3)Finder(システム関連...)
基本的には、ウィンドウ上にドラッグ対象オブジェクトが表示されているとすると、その上でマウスクリックが起こる時点でSend処理へと入ります。最初に、そのSend処理への入り口を紹介しておきます。ここでは、あるコントロールにドラッグ画像(PICTやICON)が表示されており、それをユーザがマウスクリックしたと仮定します。この場合には、コントロール自体にイベントハンドラ(Carbon Event Handler)を実装しておき、そこでマウスクリックの発生を感知するのが便利です。以下が、対象コントロールにイベントハンドラを実装するsetupMyControlEvent()ルーチンです。受け取り対象となるイベントの種類は「kEventControlHit」のみとなります。

次に紹介するのが、コントロール上のマウスクリックに対処するためのイベントハンドラmyControlEventHandler()ルーチンです。イベントクラスが「kEventClassControl」で、イベント種類が「kEventControlHit」の場合にのみ、ConvertEventRefToEventRecord()でEventRefの内容をEventRecord(旧イベントループで用いた構造体)へと変換し、それを対象ウィンドウのWindowRefと対象コントロールのControlRefと共にstartMyDrag()に渡しています。

実際にドラッグ&ドロップのSend処理を担当しているのがstartMyDrag()ルーチンです。本ソースコードでは、先頭が大文字のルーチンがDrag Manager APIであり、先頭が小文字のルーチンは自作ルーチンですので御注意ください。まず最初に、WaitMouseMoved()を実行します。このAPIはクリックされたマウスカーソルが動き出す(ドラッグされる)かどうかを監視しています。もし、マウスが初期位置から許容範囲外(縦横数ピクセル)へ動くと実際のSend処理へ入ります。このように、マウスドラッグへ入るまでに「数ピクセルの遊び」があるのは、ユーザインターフェース的にとても優れた仕様です(Finderで試してみると分かる)。別環境で「マウス操作がとても難しい!」と感じたならば、この「遊び」の存在をぜひ思い出してください(笑)。

WaitMouseMoved()によりマウスドラッグが関知されると、だいたい以下の手順でSend処理が進んで行きます。「オプション」の記述がある番号は、ケースによっては実装しなくても全体の処理に影響がない行程です。
(1)NewDrag()で新規DragReferenceを得てセッションを開始する
(2)ドラッグ&ドロップしたいデータをセッションに登録する
(3)ドラッグするオブジェクトのグレイ枠(Region)を作成する
(4)ドラッグ中表示される半透明の画像を作成する(オプション)
(5)データ受け渡し用コールバックルーチンを登録する(オプション)
(6)TrackDrag()でドラッグ&ドロップのSend処理を開始する
(7)セッションの後処理を実行する(オプション)
次回は、上記の処理を手順を追って説明して行きます。まずは、startMyDrag()内で実行されているcreateDataMyDrag()ルーチンを解説します。ドラッグされるデータ種類を色々と変えることで処理ルーチンがどう変わるかを、例題を上げて紹介したいと思います。
copyright 2005 Ottimo, Inc. All rights reserved
無断転載・引用禁止
Contact us: koike@ottimo.co.jp