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でプロパティを扱ったサンプルが無かったので入れてみました。
 xSendEvt は HyperTalk からメッセージを send された時の処理です。HyperTalk から命令を受けて自前のウィンドウがリアクションするのはなんだか楽しいです。
 今回はパレットウィンドウとして作るので、xHidePalettesEvt と xShowPalettesEvt にも対応することにします。


 ここに出てくる xWEventPtr& という引数は、HyperCard から送られて来たイベント情報を収めたメモリブロックのポインタです。この構造体の中身は以下のようになっています。
DIM RECORD xWEventInfo
  DIM evnt;_evtblksize
  DIM evntWindow&
  DIM evntParams;36
  DIM evntResult&
DIM END RECORD .xWEventInfo
 第1フィールド evnt はマック標準のイベントレコードです。イベントの情報を詳しく知りたい場合はこの evnt レコードの中身を読みます。詳しくは ToolBox 解説書のイベント処理の項参照のこと。
 第2フィールド evntWindow& はイベントが起きたウィンドウのポインタです。
 第3フィールド evntParams は HyperCard から渡されたイベント関連のパラメータです。倍精度整数( LongInt )が9つ並んでおり、xSendEvt と xGetPropEvt、xSetPropEvt で使います。
 第4フィールドはイベントの処理結果を HyperCard に返すためのものです。 xGetPropEvt で使います。



 以下、各イベント処理ルーチンの中身を書いて行きます。

・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 が送られて来た時にウィンドウを表示する
 処理をしています。



 以上で Events ファイルの書き換えは終わりです。

 それぞれのイベントに BEEP を入れたり、イベント処理を削除したりすると、いつどのルーチンが実行されているのか、実行しないとどうなるかが分かって面白いと思います。

 あとは XCMD 作成手順に従ってコンパイルし、メッセージリソースを整えれば完成です。おっとテスト用にピクトリソースを入れておくこともお忘れ無く。



 テストする時はメッセージボックスから picPalette "myPic", "50,50" のように実行して下さい。第2引数をクォートで囲わないと、引数が3つと判断されてしまいます。ピクトを表示したウィンドウが開きましたね。

 メッセージを受け取れるかをテストするために、send "flash" to window "myPic" を実行してみて下さい。ウィンドウが3回フラッシュします。

 プロパティを処理できるかテストするために、put the creator of window "myPic" を実行してみて下さい。最初は初期値である "Who" が表示されます。次にプロパティをセットするために set the creator of window "myPic" to "UDI" を実行します。再度プロパティを表示させると、今度は "UDI" が表示されます。


inserted by FC2 system
Next



FutureBASIC Lab.

UDI's HomePage