Hey guys, in the previous part of the series we turned our so-called screens into real screens. To work with screens, we need screen managers, two in our case, but generally at least one screen manager is necessary.
Table of Contents
Book Info
The ScreenManager Class
A screen manager is an object of the ScreenManager class that handles the transitions from one screen to another.
In our app we will need two screen managers. The first one will switch between the Settings screen, Race screen and Game Over screen. These are the screens that will take up the whole space of the app window. But then we’ll need another screen manager that will switch between the Bets screen and the Results screen inside the Race screen.
We’re going to take care of the former in this part of the series and handle the latter in the next part.
The main.py File
When you open the main.py file, you will see the following code:
# File name: main.py
import kivy
from kivy.app import App
class SlugraceApp(App):
def build(self):
pass
if __name__ == '__main__':
SlugraceApp().run()
This is actually the place where our app will start. When our screen system is up and running, we won’t be running the five screens separately, as we’re doing now, but rather from one location, which is right here.
The build method must return something. It’s going to return a ScreenManager object that we’re just about to create. So, here’s how we do it:
# File name: main.py
import kivy
from kivy.app import App
# We need to import the ScreenManager class.
from kivy.uix.screenmanager import ScreenManager
# We'll also add the configuration code here,
# so we must import the Config class, like we did
# in all the other Python files before.
from kivy.config import Config
# Here's the configuration.
Config.set('graphics', 'width', '1200')
Config.set('graphics', 'height', '675')
Config.set('graphics', 'resizable', '1')
# Now we must define a screen manager class that
# inherits from ScreenManager.
class SlugraceScreenManager(ScreenManager):
# We'll implement it in the kv file.
pass
class SlugraceApp(App):
def build(self):
# The method should return the screen manager.
return SlugraceScreenManager()
if __name__ == '__main__':
SlugraceApp().run()
When we run the app now, we will see just a black app window. This is because a ScreenManager is returned that hasn‘t been implemented yet. We’re going to implement it in the kv file. As you can see, the name of the app is SlugraceApp, so, following the naming convention discussed before, the kv file should be called slugrace.kv. So, let’s create the file and put the following code in it:
# File name: slugrace.kv
# Here's our screen manager. It should contain
# the three full-window screens. Each screen
# must have a name so that we can then
# reference it.
<SlugraceScreenManager>:
SettingsScreen:
name: 'settingsscreen'
RaceScreen:
name: 'racescreen'
GameoverScreen:
name: 'gameoverscreen'
In the code above you can see that our screen manager widget contains three screens. By default it will use the first one, so SettingsScreen. But there are still a couple of things we must do. First of all we must load the kv files of the three screens in the Python file. Second, we must import the Python files in the kv files, which is something new that we haven’t done before. So, let’s start with the former, we already did it before:
# File name: main.py
import kivy
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager
from kivy.config import Config
# We need the Builder class to load kv files.
from kivy.lang import Builder
# Configuration
Config.set('graphics', 'width', '1200')
Config.set('graphics', 'height', '675')
Config.set('graphics', 'resizable', '1')
# We must load the kv files of the three screens.
Builder.load_file('settings.kv')
Builder.load_file('race.kv')
Builder.load_file('gameover.kv')
class SlugraceScreenManager(ScreenManager):
pass
class SlugraceApp(App):
def build(self):
return SlugraceScreenManager()
if __name__ == '__main__':
SlugraceApp().run()
But this is not enough for the app to work. If tou ran it now, you would get errors informing you that SettingsScreen, RaceScreen and GameoverScreen are unknown classes. So, now we have to inform the corresponding kv files what they are, which we do by importing the Python files in the kv files.
Importing in kv File
To import Python modules and classes in the Kivy language, there’s a special syntax for that:
#:import alias name
It looks like a comment, but as you can see there’s a colon folowing the # sign. Unlike in Python code, the alias comes first and only then the name of the module or class without the .py extension. So, for example if you wanted to import the numpy module, you would do it like so:
#:import np numpy
This is equivalent to:
import numpy as np
in Python.
So, now that you know how to import stuff in kv, we can import the Python files. In kv we must use an alias, which is not required in Python, so often you just repeat the name of the module as the alias in Kivy. This is how we are going to import the settings.py file in the settings.kv file:
#:import settings settings
So, we’re importing the settings module with the alias settings. Now the settings.kv file should look like this:
# File name: settings.kv
#:import settings settings
<PlayerCount>:
...
<PlayerSettings>:
...
<SettingsScreen>:
...
Similarly, let’s import the appropriate modules in the other two kv files. Here’s the race.kv file:
# File name: race.kv
#:import race race
<SlugStats>:
...
<PlayerStats>:
...
<SlugInfo>:
...
<SlugImage>:
...
<RaceScreen>:
...
And here’s the gameover.kv file:
# File name: gameover.kv
#:import gameover gameover
<GameoverScreen>:
...
So, with the modules imported, the screen manager should display the first screen on its list, so the Settings screen. Here’s what we get when we run the app from the main.py file:
Although the app works, in the terminal you can see quite a few errors and warnings. Some of them are related to the fact that the widgets.kv file is loaded multiple times. We’ll handle this in the one of the following parts of the series. And now let’s make the screen manager actually switch the screens.
Switching Screens
As I said, the first screen in the screen manager is used by default if not otherwise specified. But how do we switch to another screen? When we press the Ready button in the Settings screen, we want to switch to the Race screen. To do that we must somehow reference the screen manager and set its current property to the name of the screen. You can access a screen’s manager by using the manager property on the Screen object. Each screen has the manager property which is used to access the instance of the screen manager.
So, in the settings.kv file let’s locate the Ready button and set the manager’s current property to indicate the Race screen. We have to use the name of the screen that we defined before:
# File name: settings.kv
#:import settings settings
...
<SettingsScreen>:
...
### READY BUTTON ###
RedButton:
text: 'Ready'
on_press: root.manager.current = 'racescreen'
Now if you run the app (from now on we’ll be always running the app from the main.py file), the Settings screen will appear again. Let’s press the Ready button and we should switch to the Race screen. And now let’s make the screen manager switch to the Game Over screen when we press the End Game button in the Race screen. You will find the code in the race.kv file. Here’s what we have to add:
# File name: race.kv
#:import race race
...
<RaceScreen>:
...
# Buttons
BoxLayout:
...
RedButton:
text: 'End Game'
pos_hint: {'right': 1}
on_press: root.manager.current = 'gameoverscreen'
RedButton:
...
Now when you run the app and press the Ready button, you will switch to the Race screen. In the Race screen you can now press the End Game button and you will switch to the Game Over screen.
Finally, in the Game Over screen, we want to switch back to the Settings screen when the Play Again button is pressed, which will also close the cycle of switches between screens in our app, at least the full-window screens. Here’s the code in the gameover.kv file:
# File name: gameover.kv
#:import gameover gameover
<GameoverScreen>:
...
# The buttons
BoxLayout:
...
RedButton:
text: 'Play Again'
pos_hint: {'x': 0, 'center_y': .5}
on_press: root.manager.current = 'settingsscreen'
RedButton:
...
Try it out. You should now be able to switch from the Settings screen to the Race screen, from the Race screen to the Game Over screen and from the Game Over screen back to the Settings screen. We’re not yet done with the code, there’s quite a lot of code to refactor, which we’ll take care of later on, but now, in the next part of the series, we will implement the other screen manager, so the one that switches between the Bets screen and the Results screen inside the Race screen.
Finally, I was w8ing a long time for this part 😀 Thx Bro!