Hey guys, in the previous part of the series we created the Game class, or rather renamed the SlugraceScreenManager class that we had defined long before. This is the class most of our game logic will go into. Part of the logic is that if we do something, like press a button or check a radio button, something should happen. This is what events are for. Yes, in this part we’re going to talk about events in Kivy. But before we start, here’s some info for you.
Table of Contents
Book Info
And Now Let’s Move On…
We’ve been using events a lot since the beginning of this series. In this part we’ll try to systematize what we know about the basic usage of events in Kivy. Let’s take a break from the Slugrace project and use the test files (test.py and test.kv) for a while to practice events.
Overriding Existing Event Methods
Let’s rewrite our test files. Here’s the Python code:
# File name: test.py
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
from kivy.properties import NumericProperty
from kivy.uix.button import Button
# Configuration
Config.set('graphics', 'width', '1200')
Config.set('graphics', 'height', '675')
Config.set('graphics', 'resizable', '1')
class CustomButton(Button):
counter = NumericProperty(1)
class TestLayout(BoxLayout):
pass
class TestApp(App):
def build(self):
return TestLayout()
if __name__ == '__main__':
TestApp().run()
And here’s the kv file:
# File name: test.kv
<CustomButton>:
font_size: 50
size_hint_x: .5
text: str(self.counter)
<TestLayout>:
CustomButton:
CustomButton:
If you run the app, you will see the two buttons next to each other:
The Button class has two methods which you already know, on_press and on_release. You can redefine them, so override their functionality. You can do it in two ways, either for the whole class (then they will be redefined for all instances of the class) or just for a single instance.
If you want the on_press event to do something on one instance only, you can easily do it in kv code. Let’s define a simple functionality that increases the counter value for the second button when it’s pressed. All you have to do is define the on_press event on just that button:
# File name: test.kv
<CustomButton>:
font_size: 50
size_hint_x: .5
text: str(self.counter)
<TestLayout>:
CustomButton:
CustomButton:
on_press: self.counter += 1
Now if you run the program and click on the second button, the counter value will change. But it won’t change if you press the first button:
You can also define an event on each instance individually so that it works in a different way. Have a look at this:
# File name: test.kv
<CustomButton>:
font_size: 50
size_hint_x: .5
text: str(self.counter)
<TestLayout>:
CustomButton:
on_press: self.counter -= 1
CustomButton:
on_press: self.counter += 1
Now the counter will be increased on the second button, but decreased on the first one:
If you want the event to work the same for all instances, a better solution that defining it on each instance and thus making the code repetitive, is to define it in the class rule or in Python code. Suppose we want the counter value to be increased on any instance of the button when pressed. Here’s how we can do it in kv:
# File name: test.kv
<CustomButton>:
font_size: 50
size_hint_x: .5
text: str(self.counter)
on_press: self.counter += 1
<TestLayout>:
CustomButton:
CustomButton:
Now if you run the app and press both buttons several times, you will see something like this:
Alternatively, you could remove the code from the kv file and put it in the Python file:
# File name: test.py
...
class CustomButton(Button):
counter = NumericProperty(1)
def on_press(self):
self.counter += 1
class TestLayout(BoxLayout):
...
You can also put the code in both Python code and kv code. For example, if we want the counter value to be increased for each button, but additionally we want the font size to be increased only on the second button, we can put the shared behavior in the Python file (or in the class rule in kv) and the individual behavior on the particular instance in kv. Here’s how we can do it. First, the Python code:
# File name: test.py
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
from kivy.properties import NumericProperty
from kivy.uix.button import Button
# Configuration
Config.set('graphics', 'width', '1200')
Config.set('graphics', 'height', '675')
Config.set('graphics', 'resizable', '1')
class CustomButton(Button):
counter = NumericProperty(1)
# This will work for each button.
def on_press(self):
self.counter += 1
class TestLayout(BoxLayout):
pass
class TestApp(App):
def build(self):
return TestLayout()
if __name__ == '__main__':
TestApp().run()
And here’s the kv file:
# File name: test.kv
<CustomButton>:
font_size: 50
size_hint_x: .5
text: str(self.counter)
<TestLayout>:
CustomButton:
CustomButton:
# This will work only on this button.
on_press: self.font_size += 10
If you now run the program and press the two buttons several times, you will see the following:
Here we’ve been working on the Button’s on_press event only, but naturally you can override any other event method on any other widget like that.
Triggering Methods
In the previous example we just changed the button’s counter and font_size properties by passing some simple Python code directly in kv. But sometimes we need something more complex to happen each time an event is triggered. If this is the case, we can define a method in the Python file and call it from the kv file.
Here we’re defining a method in the CustomButton class:
# File name: test.py
...
class CustomButton(Button):
counter = NumericProperty(1)
def reset_counter(self):
self.counter += 1
if self.counter > 5:
self.counter = 1
class TestLayout(BoxLayout):
...
And here we’re calling it from the kv file when the second button is pressed:
# File name: test.kv
<CustomButton>:
font_size: 50
size_hint_x: .5
text: str(self.counter)
<TestLayout>:
CustomButton:
CustomButton:
# This will work only on this button.
on_press: self.reset_counter()
If you now run the app, the counter will be reset back to 1 each time its value exceeds 5.
***
There’s much more to propreties than that. You can find more examples in my book. Also in my book I’m explaining how to bind and unbind events using the bind and unbind methods. I’m not going to discuss these two methods in this series, but we might occasionally be using them in the future. If so, I’ll explain what the code does and how it works when necessary.