X作成講座 on FB[09] 外部ウィンドウ パレット編[2]
さてさてイベント処理です。
このへんに来ると、もぉFBでもCでも CompileIt! でも大差ありません。どういうイベントが来た時に何をどう処理するのかは、ほとんどオヤクソクで決まっています。
FBがC言語に比べて便利だなと思うのは、文字列(ただし255バイトまで)の扱いがラクだと言うことです。これだけでも結構助かりますね。
まず今回書き換える HyperXcmd Events.INCL(以下 Events ファイル)を開いて下さい。
自前の構造体(レコード)を使うために、グローバルファイルを読み込みます。
GLOBALS "HyperXcmd.GLBL"
のあとに
GLOBALS "myX.GLBL"
の1行を書き加えて下さい。
次に一番下にある LOCAL FN HandleHCEvent ルーチンを書き換えます。ここは HyperCard から送られてきたイベントを、イベントの種類ごとに各ルーチンに振り分ける処理をしています。今回は扱うイベントを少し増やします。
CASE _kHighLevelEvent
と
CASE ELSE
の間に以下の CASE 文を入れて下さい。
CASE _xGetPropEvt : FN DoGetPropEvt(xCmdPtr&, xWEventPtr&) CASE _xSetPropEvt : FN DoSetPropEvt(xCmdPtr&, xWEventPtr&) CASE _xSendEvt : FN DoSendEvt(xCmdPtr&, xWEventPtr&) CASE _xHidePalettesEvt : FN DoHidePalettesEvt(xCmdPtr&, xWEventPtr&) CASE _xShowPalettesEvt : FN DoShowPalettesEvt(xCmdPtr&, xWEventPtr&)xGetPropEvt と xSetPropEvt は独自のプロパティを作るときに使います。多少高度なプログラミングの部類に入りますが、FBでプロパティを扱ったサンプルが無かったので入れてみました。
DIM RECORD xWEventInfo DIM evnt;_evtblksize DIM evntWindow& DIM evntParams;36 DIM evntResult& DIM END RECORD .xWEventInfo第1フィールド evnt はマック標準のイベントレコードです。イベントの情報を詳しく知りたい場合はこの evnt レコードの中身を読みます。詳しくは ToolBox 解説書のイベント処理の項参照のこと。
・DoOsEvt LOCAL FN DoOsEvt (xCmdPtr&, xWEventPtr&) xWndPtr& = xWEventPtr&.evntWindow& theMsg& = [ xWEventPtr& +_evnt +_evtMessage ] myFlag% = FN BITTST( theMsg&, 31 ) ' test bit 0 LONG IF myFlag% CALL SHOWWINDOW( xWndPtr& ) XELSE CALL HIDEWINDOW( xWndPtr& ) END IF xCmdPtr&.passFlag% = _zTrue END FN ここはアプリがアクティブ/デアクティブになった時の処理をしています。 パレットウィンドウはデアクティブ時に HideWindow し、アクティブ時に ShowWindow するのがオヤクソクです。 アクティブになったのか、デアクティブになったのかはイベントレコードの message(FBでは _evtMessage )の第0ビットを調べれば分かります。 ToolBox 関数 BitTst はビットを上下逆に数えるので、第0ビットを調べる 時は第2引数に31を渡します。もし第1ビットを調べるなら30ですね。 ・DoUpdateEvt LOCAL FN DoUpdateEvt (xCmdPtr&, xWEventPtr&) xWndPtr& = xWEventPtr&.evntWindow& myDataHand& = FN GETWREFCON( xWndPtr& ) CALL BEGINUPDATE( xWndPtr& ) CALL SETPORT( xWndPtr& ) CALL DRAWPICTURE( myDataHand&..fPicHand&, xWndPtr&.portRect& ) CALL ENDUPDATE( xWndPtr& ) xCmdPtr&.passFlag% = _zTrue END FN ウィンドウの再描画処理をするルーチンです。 ウィンドウの refCon から自前のデータを取り出し、そのピクトをウィンドウの 大きさで描画します。クリッピング(他のウィンドウに隠れている部分の処理) などは全てシステムがやってくれるので、単にウィンドウの中身を全部描いて しまえばOKです。 ピクトのハンドルは myDataHand&..fPicHand& で得ています。 ハンドル経由でフィールドを読むにはドット(.)を2つ使うことに注意。 ウィンドウの大きさは xWndPtr&.portRect& で得られます。 ・DoOpenWEvent LOCAL FN DoOpenWEvent (xCmdPtr&, xWEventPtr&) xWndPtr& = xWEventPtr&.evntWindow& CALL SHOWWINDOW( xWndPtr& ) FN XWAllowReEntrancy( xCmdPtr&, xWndPtr&, _zTrue, _zTrue ) FN XWAlwaysMoveHigh( xCmdPtr&, xWndPtr&, _zTrue ) CALL INVALRECT ( xWndPtr&.portRect& ) xCmdPtr&.passFlag% = _zTrue END FN ウィンドウが開いた直後に1度だけ実行されるルーチンです。 作成時に visible を _false にした場合はここで ShowWindow します。 (或いは HyperTalk から show window するまで放っておくことも出来ます) XWAllowReEntrancy、XWAlwaysMoveHigh、INVALRECT はオヤクソクと思って 実行するようにして下さい。 nullEvt を使いたい時はグルールーチンの SetXWIdleTime もここで実行します。 ・DoCloseWEvent LOCAL FN DoCloseWEvent (xCmdPtr&, xWEventPtr&) xWndPtr& = xWEventPtr&.evntWindow& myDataHand& = FN GETWREFCON( xWndPtr& ) CALL KILLPICTURE( myDataHand&..fPicHand& ) err% = FN DISPOSHANDLE( myDataHand&..fCreatorHand& ) err% = FN DISPOSHANDLE( myDataHand& ) xCmdPtr&.passFlag% = _zTrue END FN ウィンドウが閉じられる直前に実行されるルーチンです。 ウィンドウ破棄に伴って、自前のハンドルを破棄しています。 ・DoGetPropEvt LOCAL FN DoGetPropEvt (xCmdPtr&, xWEventPtr&) xWndPtr& = xWEventPtr&.evntWindow& propName$;255 = [ xWEventPtr& + _evntParams ] propName$ = UCASE$( propName$ ) LONG IF propName$ = "CREATOR" myDataHand& = FN GETWREFCON( xWndPtr& ) creatorHand& = myDataHand&..fCreatorHand& xWEventPtr&.evntResult& = FN HANDTOHAND( creatorHand& ) xCmdPtr&.passFlag% = _false EXIT FN END IF xCmdPtr&.passFlag% = _zTrue END FN ウィンドウのプロパティを HyperTalk に返す処理をするルーチンです。 このウィンドウは "creator" というプロパティをサポートします。 HyperTalk から get the creator of window xxx が実行された時に、ウィンドウに 保存されていた値を返しています。 プロパティ名は propName$;255 = [ xWEventPtr& + _evntParams ] という行で propName$ に受け取っています。これはそういうものとして覚えて下さい。 大文字小文字に対応するために UCASE$ してから比較しています。 プロパティが対応するものだったら自前のデータ(C文字列ハンドル)を xWEventPtr&.evntResult& に書き込み、xCmdPtr&.passFlag% を _false にします。 この手順でいくつでもプロパティを作れます。 対応しないプロパティの場合は xCmdPtr&.passFlag% を _zTrue にすれば、あとは HyperCard が対応します。 このルーチンはオリジナルには無いので新たに作って下さい。 ・DoSetPropEvt LOCAL FN DoSetPropEvt (xCmdPtr&, xWEventPtr&) xWndPtr& = xWEventPtr&.evntWindow& propName$;255 = [ xWEventPtr& + _evntParams + 0 ] propName$ = UCASE$( propName$ ) propValueHand& = [ xWEventPtr& + _evntParams + 4 ] LONG IF propName$ = "CREATOR" myDataHand& = FN GETWREFCON( xWndPtr& ) err% = FN DISPOSHANDLE( myDataHand&..fCreatorHand& ) myDataHand&..fCreatorHand& = FN HANDTOHAND( propValueHand& ) xCmdPtr&.passFlag% = _false EXIT FN END IF xCmdPtr&.passFlag% = _zTrue END FN ウィンドウのプロパティを HyperTalk からセットする処理をするルーチンです。 HyperTalk から set the creator of window xxx to yyy が実行された時に、 ここが実行されます。 プロパティ名は DoGetPropEvt と同じ手順で得られます。 セットするプロパティ値は [ xWEventPtr& + _evntParams + 4 ] で得られる C文字列ハンドルに入っています。必要ならFB文字列や数値に変換して使いますが、 ここではこのハンドルをそのまま myDataHand&..fCreatorHand& にコピーしています。 いらなくなった元のハンドルを破棄するのをお忘れなく。 プログラム中で対応した場合は xCmdPtr&.passFlag% に _false を、 HyperCard に任せる場合は xCmdPtr&.passFlag% に _zTrue を書き込みます。 このルーチンはオリジナルには無いので新たに作って下さい。 ・DoSendEvt LOCAL FN DoSendEvt (xCmdPtr&, xWEventPtr&) xWndPtr& = xWEventPtr&.evntWindow& sendMsg$;255 = [ xWEventPtr& + _evntParams ] sendMsg$ = UCASE$( sendMsg$ ) LONG IF sendMsg$ = "FLASH" CALL SETPORT( xWndPtr& ) FOR i = 1 TO 6 myTicks& = FN TICKCOUNT + 4 CALL INVERTRECT( xWndPtr&.portRect& ) WHILE FN TICKCOUNT < myTicks& WEND NEXT xCmdPtr&.passFlag% = _false EXIT FN END IF xCmdPtr&.passFlag% = _zTrue END FN HyperTalk からメッセージを send された時に処理するルーチンです。 このウィンドウでは send "flash" to window xxx を実行された時に、ウィンドウを 3回フラッシュさせています。 send されたメッセージは DoGetPropEvt と同じ手順で得られます。 このルーチンはオリジナルには無いので新たに作って下さい。 ・DoHidePalettesEvt LOCAL FN DoHidePalettesEvt(xCmdPtr&, xWEventPtr&) xWndPtr& = xWEventPtr&.evntWindow& CALL HIDEWINDOW( xWndPtr& ) xCmdPtr&.passFlag% = _zTrue END FN 今回作るのはパレットウィンドウなので、_xHidePalettesEvt イベントが 送られて来た時にウィンドウを hide する処理を入れました。 パレットの用途によっては必ずしも行う必要はないでしょう。 ・DoShowPalettesEvt LOCAL FN DoShowPalettesEvt(xCmdPtr&, xWEventPtr&) xWndPtr& = xWEventPtr&.evntWindow& CALL SHOWWINDOW( xWndPtr& ) xCmdPtr&.passFlag% = _zTrue END FN 同様に、_xShowPalettesEvt が送られて来た時にウィンドウを表示する 処理をしています。