tips

Kivyのget_property_observers: 引数付きコールバック関数でmethod_nameを取得できない現象

この記事は約7分で読めます。

Kivyのget_property_observers()で引数付きのコールバック関数をバインドした場合にmethod_nameを取得できない問題について言及しています。

get_property_observers()

get_property_observers()はプロパティまたはイベントにバインドされているコールバック関数のリストを返すメソッドで、バインドされているコールバック関数を調べることができます。

get_property_observers()メソッドの詳細とサンプルコードは下記をご覧ください。

このメソッドのパラメータにargs = Trueを指定すると下記のようなリストを返します。

[<WeakMethod proxy=<__main__.RootWidget object at 0x00000164BC361240> method=None method_name=on_callback>]

method_nameにコールバック関数名が入っています。これは引数なしのコールバック関数をバインドした時のリストになります。引数を持つコールバック関数の場合、method_nameがNoneまたは要素が存在しないという現象になったのでここにメモとして残しておきます。

method_nameが取得できない現象

引数付きのコールバック関数の場合、method_nameを取得できませんでした。弱参照が関係してるのか、バグなのか、私が悪いのか、この問題は解決できませんでした。どなたかこの現象が分かる方コメント頂けると幸いです。

bind()を使用した場合

# bindの場合 引数あり
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from functools import partial
from kivy.lang import Builder

kv_code = Builder.load_string('''
<RootWidget>:
    orientation: 'vertical'       
    Button:
        id: button2
        text: "Unbind Callback"
        font_size: 30
        on_press: root.unbind_callback()
''')

class RootWidget(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.register_event_type('on_custom_event')
        self.bind(on_custom_event=partial(self.on_callback,'args1','args2',kwargs='kwargs'))
        

    # カスタムイベント1
    def on_custom_event(self,*args):
        print('on_custom_eventが呼ばれました')

    # コールバック
    def on_callback(self, *args, **kwargs):
        print('on_callbackが呼ばれました')


    # コールバック関数のbindを解除する。
    def unbind_callback(self):
        print(self.get_property_observers('on_custom_event', args = True))
        #self.funbind('on_custom_event',self.on_callback,'args1','args2',kwargs='kwargs')

class KivyEventsCustomEvent3(App):
    def build(self):
        return RootWidget()

if __name__ == '__main__':
    KivyEventsCustomEvent3().run()

bind()でコールバック関数に引数を指定するとmethod_name=Noneになります。そして引数が収まるべき要素に入ってません。インデックス2にargs、インデックス3にkwargsが入るのが正しいはず。

# bindの場合 引数あり
[(<WeakMethod proxy=None method=functools.partial(<bound method RootWidget.on_callback of <__main__.RootWidget object at 0x00000264A5C87D90>>, 'args1', 'args2', kwargs='kwargs') method_name=None>, (), {}, 1, None)]

fbind()を使用した場合

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder

kv_code = Builder.load_string('''
<RootWidget>:
    orientation: 'vertical'       
    Button:
        id: button2
        text: "Unbind Callback"
        font_size: 30
        on_press: root.unbind_callback()
''')

class RootWidget(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.register_event_type('on_custom_event')
        self.fbind('on_custom_event',self.on_callback,'args1','args2',kwargs='kwargs')     

    # カスタムイベント1
    def on_custom_event(self,*args):
        print('on_custom_eventが呼ばれました')

    # コールバック
    def on_callback(self, *args, **kwargs):
        self.ids.label.text += '\n on_callbackが呼ばれました'

    # コールバック関数のbindを解除する。
    def unbind_callback(self):
        print(self.get_property_observers('on_custom_event', args = True))
        #self.funbind('on_custom_event',self.on_callback,'args1','args2',kwargs='kwargs')

class KivyEventsCustomEvent3(App):
    def build(self):
        return RootWidget()

if __name__ == '__main__':
    KivyEventsCustomEvent3().run()

fbind()にした場合method_nameが消えました。しかし、引数は収まるべき要素に入っています。インデックス2にargs、インデックス3にkwargsが入るのが正しい。

# fbindの場合 引数あり
[(<bound method RootWidget.on_callback of <__main__.RootWidget object at 0x00000262DA867D90>>, ('args1', 'args2'), {'kwargs': 'kwargs'}, 0, 1)]

Comment

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