2007年9月8日土曜日

wxPythonイベント関係のまとめ1

wxPythonはがんばっていると思うが、イベント処理がまだ不満ではある。
特にWindow, Frame, Panel, Controlのフォーカスとイベントの関係がわかりにくい。

MouseEvent (EVT_LEFT_UP, EVT_LEFT_DOWN, 他)マウスイベントはマウスがヒットした最前面のオブジェクトからイベントが発生する。
よくある作りでは、オブジェクトがApp - Frame - Panel - Controlの階層で配置されることが多いが,
MouseEventは上記でいうと右から順番にマウスが当たっているかどうか判断すし、当たっていたらイベントを発生させる。ちなみに、マウスクリックをしたオブジェクトは必ずしも即座にフォーカスがセットされない。例えば別のウィンドウから別のウィンドウのパネルをクリックしたとしても、パネルがフォーカスされない場合がある。なぜかはわからない。
ちなみにドラッグなどの操作をしたい場合に、window.CaptureMouse()を実行すると、window.ReleaseMouse()が発生されるまで、マウスイベントがwindow宛に送られる。これによってウィンドウ外などへマウスが逃げても処理が実行できるようになる。
window.ReleaseMouse()はキャプチャしていたマウスを見失った状態で呼ぶと例外が発生するので、
window.HasCapture()とセットで使うと良い。

KeyEvent(EVT_KEY_UP, EVT_KEY_DOWN, 他)キーイベントは現在フォーカスが当たっているオブジェクトからイベントが発生する。キーイベントをバインドする際に、このフォーカスが曲者である。
マウスクリックやTABキーなどでころころフォーカスが変わるのだが、
特にwx.Panelなどにバインドする際は注意が必要である。
wx.Panelでデフォルトで設定されているwx.TAB_TRAVERSALというスタイルがあり、これはTABキーでフォーカスを移動させていく。TextCtrlで移動するのはわかるが、デフォルトのままにしておくとパネルのフォーカスも順に移動してしまう。このため、ある一つのパネルにイベントハンドラをバインドしていても、動いたり動かなかったりするように見える。styleからwx.TAB_TRAVERSALを任意ではずすと、TABキーを押しても別のオブジェクトへフォーカスは移動はしない。

Skip()の意味Skip()は、イベントを受け取ったオブジェクト内で、他のプロセスイベントを探しに行く。例えば

self.button = wx.Button(self, -1, "Button")
self.button.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)

def OnLeftDown(self, event):
event.Skip()

とあったとすると、このSkip()は次に何を探しにいくかと言うと、同じself.buttonオブジェクトでEVT_LEFT_DOWN以外のマウスに関連するイベント(=EVT_BUTTON)を探しにいく。
なので基本的に他のオブジェクトのイベント発生には直接関係がない。wxPython in Actionの解説では、
self.buttonの親を遡ってイベントを探しに行くと成っているが、よくわからない。
ただイベントが発生したオブジェクトから順に関係のあるオブジェクトを通り、イベントハンドラがバインドされているところでは必ずSkip()を設定しておくと、最終的にはwx.Appまで通知は行くようだ。
(self.buttoが、app.frame.panel.buttonという関係だとすると、Skip()を続ければbutton>panel>frame>appと順に通知が行きそうなものだが、そうではないようだ。Propagationというのも関係がありそうだが、もう少し調査することにする。)

0 件のコメント: