buttonkivyunbind

unbinding a function to a button in kivy


Consider the following code:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button


class First(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        x = Button(text='somebutton')
        x.bind(on_press=lambda*_: print('First press'))
        x.bind(on_press=lambda*_: print('Second press'))

        self.add_widget(x)

    def something(self, *somethingishereignored):
        print("I have something")

class FChooser(App):
    def build(self):
        return First()

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

The behaviour of this code is that, after I press the 'somebutton' button, it prints:

Second press
First press

So, I googled and found that I should use the unbind() function, and I added this:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button


class First(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        x = Button(text='somebutton')
        x.bind(on_press=lambda*_: print('First press'))
        x.unbind(on_press=lambda*_: print('First press'))
        x.bind(on_press=lambda*_: print('Second press'))

        self.add_widget(x)

    def something(self, *somethingishereignored):
        print("I have something")

class FChooser(App):
    def build(self):
        return First()

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

but the output doesn't change. It's still the same output. How do I release the bind? This is just a minimal example, and I intend to use this functionality to dynamically bind and unbind a function to a button, to add various functionality to the same button.


Solution

  • The function will not unbind, because you do not refer to the function you bound to. As you use inline lambda, that method reference was not saved, so you can't use it to unbind later.
    This will work tho:

    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout
    from kivy.uix.button import Button
    
    
    class First(BoxLayout):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            x = Button(text='somebutton')
            x.bind(on_press=self.press1)
            x.unbind(on_press=self.press1)
            x.bind(on_press=self.press2)
    
            self.add_widget(x)
    
        def press1(self, *args):
            print("First press")
    
        def press2(self, *args):
            print("Second press")
    
    
    class FChooser(App):
        def build(self):
            return First()
    
    if __name__ == '__main__':
        FChooser().run()
    

    Or this:

        press1 = lambda*_: print('First press')
        press2 = lambda*_: print('Second press')
        x = Button(text='somebutton')
        x.bind(on_press=press1)
        x.unbind(on_press=press1)
        x.bind(on_press=press2)