Macintosh Programming (13) - Drag and Drop - 2000.Dec. 1. 引きずって、落っことす ドラッグアンドドロップ。です。Finderからファイルアイコンを引っぱって来て 自分のアプリのウィンドウに落っことすと反応する。って、例ですねん。 「なーんだ。それだけかよ?」とか、言わないで(;_;) Macらしいアプリには必須な機能だろうから、必ず実現するぞと不退転な意欲を 込めて頑張ったんだけど、挫折の嵐(^^;; 苦労したんだから。。。分かって>誰ぞ ソースはここ。dragdlg.lzh.bin 10,880 byte 今回のお題: ・テキストファイルをD&Dすると先頭部分だけ表示する ・そのファイルの絶対パスをリストボックスに表示する ・リストボックスをダブルクリックすると、フルパスを表示する 今回習得した技術: ・もちろんドラッグ・アンド・ドラッグ。ただしFinderからという一方通行。 しかし、それだけできれば普通はOKでないかい?(開き直り) ・リストマネージャの使用方法。そう。今回はリストボックスをリストマネージャ を使って作りました ・ダブルクリックの処理。これ、アプリ側で判断しないとダメだとは思わなかった ・テキストエディットでの日本語処理 将来(?)に持ち越した技術: ・アイコンの上にドラッグすると(アイコンが)反応する技術。これは未だ無理 2. 内容補足 絶対パスなんて、Macの場合余り意味ないですけどね。同じボリューム名のドライブが あった時に区別付かなくなるようですから。 で、何に苦労したかというと、D&Dの入り口、receive handlerの中でAlertすると95% ぐらいの割合でハングしちゃうのよね。途中までできたかどうかの確認にAlert使って いたもんだから先に進めない。最終的にAlertを全て削ることでOKでしたが。 Alert、使えるはずなんですが、何かAPIを呼べばOKだったんでしょうかね。 3. 自作関数群 /* D&D 関連 */ OSErr initDrag(/*WindowPtr win*/); OSErr unInitDrag(/*WindowPtr win*/); D&Dの初期化と後始末。Finderからの一方通行だけなので、TrackingHandlerと ReceiveHandlerのみ登録。 pascal OSErr trackHandler(DragTrackingMessage mes, WindowPtr win, DTyp* dt, DragReference dref); ドラッグ中のイベントを処理。やってきた(来つつある)データの種類(フレーバ)を チェックして、自ウィンドウ内まで来たらウィンドウの枠に色を付けてデータが 受け付けられることを示す。 この時、独自に設定した構造体にフレーバに応じたデータをセットしておく。 アイコンが遠ざかったらウィンドウ枠の色を元に戻す。 pascal OSErr receiveHandler(WindowPtr win, DTyp* dt, DragReference dref); 独自構造体(trackHandlerで自ら作った奴)を参照し、処理可能なタイプなら 受け入れ関数を呼び出す。 OSErr recvFile(WindowRef win, DragReference dref); 受け入れ関数。ウィンドウ枠の色を戻し、HFSHlavorを受け取る。 ここでファイルタイプを調べ、'TEXT'だけを(今回作った奴は)受け付ける。 そうじゃない奴はここでnoErr以外を返すことで拒否する。そうするとドロップ したアイコンが元の場所にするすると戻る。というアニメーションが自動表示 される。 void dragText(WindowRef win, FSSpec* fsp); ファイルをオープンして中身を1KBだけ読み出してTEditに表示。また、フルパスを 求めてListにセット。Listが規定の行数を超えたら先頭行を消して末尾に空白行を 追加。そこにセットするようにする。 /* TEdit, List */ Boolean doContents(WindowPtr win, EventRecord *event); ウィンドウの中身をクリックされた時の処理。TEditやListのアクティベート、 インアクティベートの処理を行う。 Boolean isDblClk(short item, long when, Point* po); 一応汎用。前回呼ばれた時と同じアイテムが規定時間内に同じ位置でクリック されたらダブルクリックとみなす。というもの。でもマウスをピクとも動かしたら アウト。というのはちと厳しすぎかも。Winだって*こんぐらいならずれてもOK* という設定があるのできっとMacもあるに違いない。けど、良く分からない。 Boolean isTSMTE(); ゲシュタルトを使ってTSMTEが使用できるかどうかを確認する。英語圏のマシンで 実行されても困らないように(笑) void doActivate(WindowPtr dlg, Boolean active); アクティベート時、TEditがアクティブなら同時にTSMDocumentもアクティブにする。 こうしないとインライン変換にならなかったんじゃないかなぁ。 void doUpdateWindow(WindowRef win); 忘れずにListをLUpdate()する。 /* その他 */ Boolean getFullPath(FSSpec* fsp, short fref, char* path); フルパス作る関数。前述した通り、余り使い道なさそうだけど(^^; void initMain(WindowPtr win); ダイアログに枠だけ(userコントロールを作っておく)置いておいたものから TextEditとListを生成する。Listって2次元の表が作れる便利なものなのだけど、 今回はあくまでリストボックスなので1次元の表とする。 int main(void); TSMTERecHandleな変数にinitMainで作ったTextEditのハンドルをセット。 今回、TextEditが1つしかないので一度セットすれば後は気にしなくて良いはず。 4. 言い訳 え?リストボックスのスクロールバーをクリックしてもスクロールしないし、 矢印キーを押しても反応しないし、テキストエディット部にスクロールバーが ないのは酷すぎる。って? いやその。それらは過去にやったことを応用するだけの話。新規性がないので 省略したのです……。(単に気力が無くなったからだと、正直に書け!!>わし) う〜。超疲れた。メモリ保護のないOSは嫌ぢゃ〜。しかしOSXはBasilisk IIじゃ動かんから のぉ。 ところで誰か余っているOS8、譲ってくれません?(爆)最近、極貧なの(;_;) #そのうちAppleが(OS7.5.5の様に)公開してくれるのでは。と淡く期待はしてるのだが。。。 (EOF)