wxPython(Phoenix) event.Skip()できないイベントで、イベントを他に渡す

要約すれば、 wx.PostEvent(dist, evt) で、イベントを明示的に伝播できます、ということです。

追記

キーボードの入力というか、操作を受け付けたい時は、 wxPython(Phoenix) キーボード操作は、wx.EVT_CHAR_HOOKを使うのが良さそう - ikap を参考にしてほしいです。以下の本記事ではwx.EVT_KEY_DOWNを利用しています。

本文

PhoenixのEventは、 Events and Event Handling — wxPython Phoenix 3.0.3 documentation によると2種類に大別できる。

wx.Eventから派生したクラスwx.CommandEventから派生したクラスである。 違いは、親にイベントを伝播できるかどうかである。前者はこれをできず、後者は可能である。

# 前者の伝播できない例
import wx
class Panel1(wx.Panel):
    def __init__(self, parent):
        super().__init__(parent)
        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDownPanel)


    def OnKeyDownPanel(self, evt):
        print('I am panel1. ここは呼ばれる')
        # これが無視されてしまう
        evt.Skip()

class Frame1(wx.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        panel = Panel1(self)
        # KeyEventはwx.Eventの派生クラスで伝播できない
        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDownFrame)
        self.SetSize(240, 300)
        self.Show()

    def OnKeyDownFrame(self, evt):
        print('I am frame1. ここは呼ばれない')

app = wx.App()
example = Frame1(None)
app.MainLoop()

は、これしか出力しない。

>>> I am panel1. ここは呼ばれる

一方で、

# 後者の例
import wx
class Button1(wx.Button):
    def __init__(self, parent):
        super().__init__(parent)
        self.SetLabelText('伝播')
        self.Bind(wx.EVT_BUTTON, self.OnPressButton)

    def OnPressButton(self, evt):
        print('I am Button1. 呼ばれるよ')
        evt.Skip()

class ExampleCommandEvent(wx.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.Bind(wx.EVT_BUTTON, self.OnPress)

        btn = Button1(self)
        # 直観的には以下のような実装するとおもいます
        # btn.Bind(wx.EVT_BUTTON, self.OnPress)
        # このようにすると、self.OnPressだけ呼べる

        self.Show()

    def OnPress(self, evt):
        print('I am ExampleCommandEvent. 伝播されたよ')

ex = wx.App()
ExampleCommandEvent(None)
ex.MainLoop()

次を出力する

>>> I am Button1. 呼ばれるよ
>>> I am ExampleCommandEvent. 伝播されたよ

まあ、後者のButtonの方はあまりしない書き方ですけども。伝播するよ、 という例を示したかっただけですので、ご容赦ください。

KeyEventがSkipできないのは個人的によろしくないので、なんとかしたい。

ありました。 wxpython - about event.Skip() - Stack Overflow

イベントをポスト出来る模様。 なので、伝播できなかったPanel1を以下のようにすれば良い

class Panel1(wx.Panel):
    def __init__(self, parent):
        super().__init__(parent)
        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDownPanel)


    def OnKeyDownPanel(self, evt):
        print('I am panel1. ここは呼ばれる')
        # これでFrameに伝わる
        wx.PostEvent(self.GetParent(), evt)

出力される:

>>> I am panel1. ここは呼ばれる
>>> I am frame1. ここは呼ばれない

要するに、CommandEventの派生クラスでない時は、wx.PostEvent(self.GetParent(), evt)すれば親に渡せる

タイトルとURLをコピーしました