Kivy - Button Events



A Button, as most of the GUI widgets in Kivy, is programmed to respond to specific types of events. A Button processes the following event types −

  • on_press − Triggered when the button is pressed.

  • on_release − Triggered when the button is released.

  • on_touch_down − Triggered when a touch event starts on the button.

  • on_touch_up − Triggered when a touch event ends on the button.

Kivy's EventDispatcher class provides a bind() method which is responsible for delegating the event to a certain callback function for processing.

EventDispatcher.bind(self, **kwargs)

Button (as does each Kivy widget) inherits this method. Hence, we can bind a Button object to any callback eventhandler function. You can also bind a property to a callback.

Binding Event

Given below is a typical way to bind the on_press event of a button is bound to a function −

def callback(instance):
   print('The button is being pressed')
   
btn1 = Button(text='Hello world')
btn1.bind(on_press=callback)

Example

In the following example, we have put two buttons inside FloatLayout. The "on_press" event of each button is bound to the callback() method.

The reference of the button on which the "on_press" event occurred is passed to the callback() method, so that we can identify the caption of the button pressed.

from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
from kivy.uix.floatlayout import FloatLayout

# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')

class ButtonApp(App):
   def on_button_press(self, instance):
      print("{} Button pressed!".format(instance.text))

   def build(self):
      flo = FloatLayout()
      btn1 = Button(text= 'Hello World',
         background_color= [1,0,0,1],
         font_size= 20, underline= True,
         size_hint= (.4, .25),
         pos_hint= {'center_x':.5, 'center_y':.8})
      btn1.bind(on_press = self.on_button_press)

      btn2 = Button(text= 'Hello Python',
         color= [0,0,1,1], font_size= 20,
         size_hint= (.4, .25),
         pos_hint= {'center_x':.5, 'center_y':.2})
      flo.add_widget(btn1)
      btn2.bind(on_press = self.on_button_press)
      flo.add_widget(btn2)
      return flo

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

Output

Run the above code and press the buttons −

Kivy Button Events1

On each press, the callback() method is invoked −

Hello World Button pressed!
Hello Python Button pressed!

Binding Property

As mentioned earlier, we can bind a callback to a property of a widget. Every time the value of the property changes, the callback is invoked to notify the change.

btn1.bind(property=callback)

Let us define another method "on_textchanged()" in the App class, and bind it with the text property of btn2. The on_press event on btn1 changes the caption of btn2, and the change invokes the on_textchanged() method immediately.

Example

Change the code for ButtonApp class as below −

from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
from kivy.uix.floatlayout import FloatLayout

# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')

class ButtonApp(App):
   def on_button_press(self, instance):
      print("{} Button pressed!".format(instance.text))
      self.btn2.text="Hello Tutorialspoint"

   def on_textchanged(self, instance, value):
      print ("Text property changed to", instance.text)

   def build(self):
      flo = FloatLayout()
      self.btn1 = Button(text= 'Hello World',
         background_color= [1,0,0,1],
         font_size= 20, underline= True,
         size_hint= (.4, .25),
         pos_hint= {'center_x':.5, 'center_y':.8})

      self.btn1.bind(on_press = self.on_button_press)
      self.btn2 = Button(text= 'Hello Python', color= [0,0,1,1],
         font_size= 20, size_hint= (.4, .25),
         pos_hint= {'center_x':.5, 'center_y':.2})
      flo.add_widget(self.btn1)
      self.btn2.bind(text = self.on_textchanged)
      flo.add_widget(self.btn2)
      return flo

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

Output

Run the code and first press btn1. It changes the caption of btn2 and it in turn calls the "on_textchanged()" method.

Hello World Button pressed!
Text property changed to Hello Tutorialspoint

Here's the output window −

Kivy Button Events2

In general, property callbacks are called with two arguments (the object and the property's new value) and "event callbacks" with one argument (the object).

Binding using Lambda Function

Another approach for binding is to use lambda (or anonymous) function. Their advantage is that you can avoid declaring new functions i.e. they offer a concise way to "redirect" callbacks.

Change the statement that binds the "on_press" event of btn1 to −

self.btn1.bind(on_press = lambda btn1: self.on_button_press(btn1))

Using Partial Function

In Python, a Partial function allows us to derive a function with x parameters to a function with fewer parameters and constant values set for the more limited function. It makes a function reusable. The partial() function is defined in functools module of Python's standard library.

Example

We can bind an event to a partial method. In the example below, the Button objects bt1 and btn2 are passed. The function interchanges the text property of the two.

from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
from kivy.uix.floatlayout import FloatLayout
from functools import partial

# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '300')
Config.set('graphics', 'resizable', '1')

class ButtonApp(App):
   def on_textchanged(self, instance, value):
      print ("Text property changed to", instance.text)

   def a_function(self, *args):
      args[0].text, args[1].text = args[1].text, args[0].text

   def build(self):
      flo = FloatLayout()

      self.btn1 = Button(text= 'Hello World',
         background_color= [1,0,0,1],
         font_size= 20, underline= True,
         size_hint= (.4, .25),
         pos_hint= {'center_x':.5, 'center_y':.8})
         
      self.btn2 = Button(text= 'Hello Python',
         color= [0,0,1,1],
         font_size= 20,
         size_hint= (.4, .25),
         pos_hint= {'center_x':.5, 'center_y':.2})
      flo.add_widget(self.btn1)
      self.btn1.bind(on_press = partial(self.a_function, self.btn1, self.btn2))
      self.btn2.bind(text = self.on_textchanged)
      flo.add_widget(self.btn2)
      return flo

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

Output

Take a look at the following output window and observe how pressing the first button interchanges the text of the two buttons −

Button Hello Word
Advertisements