In the previous part we created a very basic Settings screen, which contains all the elements that are supposed to be there in the final version, naturally without any functionality added yet. Today we’re going to rewrite the code using class rules to make our lives easier.
But before we delve into the topic, here’s some info for you.
*****
Table of Contents
Book Info
I just published my Kivy book, GUI Programming with Python and Kivy. It’s pretty long (over 800 pages) and comprehensive. And, which also counts, easy to read. The book contains lots of illustrations.
This book covers all the basics that you need to know to start programming GUI applications with Python and Kivy. Throughout the book we are building a GUI application from scratch, a fully functional game using all kinds of tools that Kivy has to offer. It’s our Slugrace project, but covered in a much more in-depth manner.
Each part of the book starts with a theoretical introduction of a topic or idea that we then implement in the project. I assume you have no prior knowledge of the Kivy library, but you should have at least some basic knowledge of the Python programming language, including the object-oriented programming paradigm as this is what we will be using a lot in this book.
The book covers all the basic elements of Kivy that you have to know, like widgets, layouts, Kivy ids and properties, graphics, screens, animation, sound. Finally we’ll deploy the app to Windows. It is pretty comprehensive and after you finish it, I’m sure you’ll be able to create your own awesome GUI apps of any kind, not just games.
I hope you will have at least as much fun reading the book as I had writing it.
As far as this Kivy series is concerned, the following parts will contain the most important elements covered in the book. However, some elements will be presented in a simplified way here on my blog or omitted completely.
____________
If you are interested, you can purchase the book in four versions. Here are the links:
1) ebook – pdf version on my website – in full color
Here you can see the description of the book, sample graphics from the book and the full table of contents.
2) ebook – Kindle version on Amazon – in full color
3) paperback version on Amazon – in black and white
4) paperback version on Amazon – in full color
*****
And Now Let’s Move On…
But first let’s have a look at what we have. Here’s the code again, first the Python file:
# File name: settings.py
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class SettingsScreen(BoxLayout):
pass
class SettingsApp(App):
def build(self):
return SettingsScreen()
if __name__ == '__main__':
SettingsApp().run()
And here’s the kv file:
# File name: settings.kv
<SettingsScreen>:
orientation: 'vertical'
padding: 10
spacing: 10
### SETTINGS LABEL ###
Label:
text: 'Settings'
font_size: 28
size_hint: (1, None)
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
### THE PLAYERS ###
BoxLayout:
orientation: 'vertical'
padding: 10
spacing: 10
# Title
Label:
text: 'The Players'
font_size: 20
size_hint: (1, None)
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
# Radiobuttons
BoxLayout:
size_hint: (.4, None)
height: 50
# 1 player
BoxLayout:
CheckBox:
group: 'players'
size_hint: (.5, 1)
Label:
text: '1 player'
text_size: self.size
halign: 'left'
valign: 'center'
# 2 players
BoxLayout:
CheckBox:
group: 'players'
size_hint: (.5, 1)
Label:
text: '2 players'
text_size: self.size
halign: 'left'
valign: 'center'
# 3 players
BoxLayout:
CheckBox:
group: 'players'
size_hint: (.5, 1)
Label:
text: '3 players'
text_size: self.size
halign: 'left'
valign: 'center'
# 4 players
BoxLayout:
CheckBox:
group: 'players'
size_hint: (.5, 1)
Label:
text: '4 players'
text_size: self.size
halign: 'left'
valign: 'center'
# Player name and initial money setup
BoxLayout:
orientation: 'vertical'
# the headers row
BoxLayout:
Label:
text: ""
size_hint_x: None
width: 80
text_size: self.size
halign: 'left'
valign: 'center'
# name header
Label:
text: "Name"
size_hint_x: None
width: 700
text_size: self.size
halign: 'left'
valign: 'center'
# money header
Label:
text: "Initial Money"
text_size: self.size
halign: 'left'
valign: 'center'
# the players rows
# player 1
BoxLayout:
Label:
text: 'Player 1'
size_hint: None, None
width: 80
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
TextInput:
multiline: False
size_hint: None, None
width: 400
height: 30
BoxLayout:
Label:
text: ""
size_hint_x: None
width: 280
text_size: self.size
halign: 'left'
valign: 'center'
Label:
text: "$"
size_hint: None, None
width: 20
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
# player 2
BoxLayout:
Label:
text: 'Player 2'
size_hint: None, None
width: 80
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
TextInput:
multiline: False
size_hint: None, None
width: 400
height: 30
BoxLayout:
Label:
text: ""
size_hint_x: None
width: 280
text_size: self.size
halign: 'left'
valign: 'center'
Label:
text: "$"
size_hint: None, None
width: 20
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
# player 3
BoxLayout:
Label:
text: 'Player 3'
size_hint: None, None
width: 80
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
TextInput:
multiline: False
size_hint: None, None
width: 400
height: 30
BoxLayout:
Label:
text: ""
size_hint_x: None
width: 280
text_size: self.size
halign: 'left'
valign: 'center'
Label:
text: "$"
size_hint: None, None
width: 20
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
# player 4
BoxLayout:
Label:
text: 'Player 4'
size_hint: None, None
width: 80
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
TextInput:
multiline: False
size_hint: None, None
width: 400
height: 30
BoxLayout:
Label:
text: ""
size_hint_x: None
width: 280
text_size: self.size
halign: 'left'
valign: 'center'
Label:
text: "$"
size_hint: None, None
width: 20
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
### ENDING CONDITIONS ###
BoxLayout:
orientation: 'vertical'
size_hint: (1, .4)
padding: 10
spacing: 10
# title label
Label:
text: "Ending Conditions"
font_size: 20
size_hint: (1, None)
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
# radio buttons
GridLayout:
rows: 3
spacing: 10
# option 1: money
CheckBox:
group: 'conditions'
size_hint_x: .05
Label:
text: "The game is over when there is only one player with any money left."
text_size: self.size
halign: 'left'
valign: 'center'
# option 2: races
CheckBox:
group: 'conditions'
size_hint_x: .05
BoxLayout:
Label:
text: "The game is over not later than after a given number of races."
text_size: self.size
halign: 'left'
valign: 'center'
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
# option 3: time
CheckBox:
group: 'conditions'
size_hint_x: .05
BoxLayout:
Label:
text: "The game is over not later than the total racing time has elapsed."
text_size: self.size
halign: 'left'
valign: 'center'
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
### READY BUTTON ###
Button:
text: 'Ready'
size_hint: (None, None)
size: 200, 40
pos_hint: {'center_x': 0.5}
Pretty long, right? Well, over 350 lines of code, including comments and blank lines. If you look closer at the code you can see right away that it’s very repetitive. This is definitely a drawback. We’re going to reduce the amount of code by extracting repetitive code into class rules. But before we do that, let’s run the program again to see what the Settings screen looks like at this stage:
Naturally, it’s not the final version yet, but today we’re not going to change anything in the visual representation of the screen, but rather just refactor the code.
Class Rules
So, let’s get to work. You already know what class rules are. We used the rule class notation when we were talking about custom widgets. So, the idea is that you can define a class rule above the root widget and then use it inside the root widget just like any other widget. I think it will be much easier to understand if we work on an example.
Custom Labels
If you look at the app window, shown in the image above, you can see there’s a lot of text. This means there are a lot of labels. As far as font size is concerned, there are three sizes of text:
– most of the text is pretty small
– the two titles (The Players and Ending Conditions) are larger
– the screen title (Settings) is even larger
Now let’s have a look at how these labels are represented in code. Here are some examples of the small font size labels:
– the label that reads ‘1 player’ in the Radiobuttons section:
Label:
text: '1 player'
text_size: self.size
halign: 'left'
valign: 'center'
– the name header:
Label:
text: "Name"
size_hint_x: None
width: 700
text_size: self.size
halign: 'left'
valign: 'center'
– one of the labels in the Ending Conditions area:
Label:
text: "The game is over not later than after a given number of races."
text_size: self.size
halign: 'left'
valign: 'center'
As you can see, all these labels share some properties:
text_size: self.size
halign: 'left'
valign: 'center'
They also have the text property, but it’s set to a different value for each label. Also, the name header label contains some more properties like size_hint_x and width. So, we can extract the three shared properties listed above into a custom label, which is a subclass of label. As this is going to be the most used label in our code, let’s name it RegularLabel. Now, above the root widget, type the following class rule that will create our custom RegularLabel class:
# File name: settings.kv
# RegularLabel inherits from Label.
<RegularLabel@Label>:
text_size: self.size
halign: 'left'
valign: 'center'
<SettingsScreen>:
...
Now, with the RegularLabel defined, we can now use this class instead of Label in our code, so the snippets above will look like so:
– the label that reads ‘1 player’ in the Radiobuttons section:
RegularLabel:
text: '1 player'
– the name header:
RegularLabel:
text: "Name"
size_hint_x: None
width: 700
– one of the labels in the Ending Conditions area:
RegularLabel:
text: "The game is over not later than after a given number of races."
So, all the repetitive code is gone and only the code that makes each label unique remains.
And now have a look at the larger font size labels used for the titles:
– The Players label:
Label:
text: 'The Players'
font_size: 20
size_hint: (1, None)
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
– Ending Conditions label:
Label:
text: "Ending Conditions"
font_size: 20
size_hint: (1, None)
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
The first thing you notice is that they also contain the code shared in the RegularLabel class, so we can create a new class that inherits from RegularLabel. Besides, there are three properties with the same values: font_size, size_hint and height, so we can move them to the new class. So, let’s add a new class rule above the root widget. The name TitleLabel sounds fine to me, so I’ll use it:
# File name: settings.kv
# RegularLabel inherits from Label.
<RegularLabel@Label>:
text_size: self.size
halign: 'left'
valign: 'center'
# TitleLabel inherits from RegularLabel.
<TitleLabel@RegularLabel>:
font_size: 20
size_hint: (1, None)
height: 30
<SettingsScreen>:
...
Now we can rewrite the title labels like so:
– The Players label:
TitleLabel:
text: 'The Players'
– Ending Conditions label:
TitleLabel:
text: "Ending Conditions"
Much more concise, isn’t it?
Now, as for the largest label with the screen title ‘Seetings’, we could create a class for it too, but let’s take a different approach this time. This label actually only differs from the title label by font size. If you set a property on a widget instance to a different value than defined in the class rule, it will overwrite it. So, here is the label as it is now in the code:
### SETTINGS LABEL ###
Label:
text: 'Settings'
font_size: 28
size_hint: (1, None)
height: 30
text_size: self.size
halign: 'left'
valign: 'center'
Let’s use our TitleLabel instead:
TitleLabel:
text: 'Settings'
font_size: 28
So, although the default font size defined in the TitleLabel class is 20, in this particular TitleLabel it is set to 28, which makes the text larger. This is how you can easily overwrite values for particular widgets.
If you scan the code carefully from top to bottom, you will see that there are some RegularLabels that still share some properties. These are:
1) the four RegularLabels with the generic names of the players, like this one:
RegularLabel:
text: 'Player 1'
size_hint: None, None
width: 80
height: 30
Here only the text should be different, so we can create a custom label with all the other properties. A characteristic feature of these labels is that they have a specific width and height, so let’s call the class Regular80x30Label. Here’s the class rule:
<Regular80x30Label@RegularLabel>:
size_hint: None, None
width: 80
height: 30
Now we can replace each occurrence of the code above with a Regular80x30Label like this:
Regular80x30Label:
text: 'Player 1'
2) the four RegularLabels with the dollar sign:
RegularLabel:
text: "$"
size_hint: None, None
width: 20
height: 30
They all have the same width and height and besides they even have the same text. So, why not create a DollarLabel class? We could derive it from RegularLabel or Regular80x30Label. Maybe the former would make more sense as the characteristic feature of the latter is its size, which is even contained in its name, but the DollarLabel and the Regular80x30Label have more properties in common, which will make the code slightly shorter, so let’s opt for the Regular80x30Label class and overwrite the width. Let’s add the following class rule:
# DollarLabel inherits from Regular80x30Label.
<DollarLabel@RegularLabel>:
text: "$"
width: 20
If we decided to subclass the RegularLabel class instead, the code would be:
# ... if DollarLabel inherited from RegularLabel...
<DollarLabel@RegularLabel>:
text: "$"
size_hint: None, None
width: 20
height: 30
As all four DollarLabels share all the properties and there are no differences between them, it’s enough to use them like this:
DollarLabel:
Now we can rewrite the whole kv file using our custom labels. Wondering how much shorter the code will become? Have a look yourself:
# File name: settings.kv
# RegularLabel inherits from Label.
<RegularLabel@Label>:
text_size: self.size
halign: 'left'
valign: 'center'
# TitleLabel inherits from RegularLabel.
<TitleLabel@RegularLabel>:
font_size: 20
size_hint: (1, None)
height: 30
# Regular80x30Label inherits from RegularLabel.
<Regular80x30Label@RegularLabel>:
size_hint: None, None
width: 80
height: 30
# DollarLabel inherits from Regular80x30Label.
<DollarLabel@Regular80x30Label>:
text: "$"
width: 20
<SettingsScreen>:
orientation: 'vertical'
padding: 10
spacing: 10
### SETTINGS LABEL ###
TitleLabel:
text: 'Settings'
font_size: 28
### THE PLAYERS ###
BoxLayout:
orientation: 'vertical'
padding: 10
spacing: 10
# Title
TitleLabel:
text: 'The Players'
font_size: 20
# Radiobuttons
BoxLayout:
size_hint: (.4, None)
height: 50
# 1 player
BoxLayout:
CheckBox:
group: 'players'
size_hint: (.5, 1)
RegularLabel:
text: '1 player'
# 2 players
BoxLayout:
CheckBox:
group: 'players'
size_hint: (.5, 1)
RegularLabel:
text: '2 players'
# 3 players
BoxLayout:
CheckBox:
group: 'players'
size_hint: (.5, 1)
RegularLabel:
text: '3 players'
# 4 players
BoxLayout:
CheckBox:
group: 'players'
size_hint: (.5, 1)
RegularLabel:
text: '4 players'
# Player name and initial money setup
BoxLayout:
orientation: 'vertical'
# the headers row
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 80
# name header
RegularLabel:
text: "Name"
size_hint_x: None
width: 700
# money header
RegularLabel:
text: "Initial Money"
# the players rows
# player 1
BoxLayout:
Regular80x30Label:
text: 'Player 1'
TextInput:
multiline: False
size_hint: None, None
width: 400
height: 30
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 280
DollarLabel:
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
# player 2
BoxLayout:
Regular80x30Label:
text: 'Player 2'
TextInput:
multiline: False
size_hint: None, None
width: 400
height: 30
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 280
DollarLabel:
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
# player 3
BoxLayout:
Regular80x30Label:
text: 'Player 3'
TextInput:
multiline: False
size_hint: None, None
width: 400
height: 30
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 280
DollarLabel:
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
# player 4
BoxLayout:
Regular80x30Label:
text: 'Player 4'
TextInput:
multiline: False
size_hint: None, None
width: 400
height: 30
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 280
DollarLabel:
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
### ENDING CONDITIONS ###
BoxLayout:
orientation: 'vertical'
size_hint: (1, .4)
padding: 10
spacing: 10
# title label
TitleLabel:
text: "Ending Conditions"
# radio buttons
GridLayout:
rows: 3
spacing: 10
# option 1: money
CheckBox:
group: 'conditions'
size_hint_x: .05
RegularLabel:
text: "The game is over when there is only one player with any money left."
# option 2: races
CheckBox:
group: 'conditions'
size_hint_x: .05
BoxLayout:
RegularLabel:
text: "The game is over not later than after a given number of races."
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
# option 3: time
CheckBox:
group: 'conditions'
size_hint_x: .05
BoxLayout:
RegularLabel:
text: "The game is over not later than the total racing time has elapsed."
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
### READY BUTTON ###
Button:
text: 'Ready'
size_hint: (None, None)
size: 200, 40
pos_hint: {'center_x': 0.5}
Looks like we reduced the code from about 350 to about 270 lines of code. Not bad. But we can reduce it even more because the labels are not the only widgets that share the same values of properties.
Custom Text Inputs
In the Settings screen there are several text inputs. There are two types of them actually:
1) the text inputs where we can enter the players’ names:
TextInput:
multiline: False
size_hint: None, None
width: 400
height: 30
2) the text inputs where we can enter numbers like the players’ initial money or the number of races or the time of the game in the Ending Conditions area:
TextInput:
multiline: False
size_hint: None, None
width: 250
height: 30
For the sake of simplicity, let’s just create two classes, NameInput and NumInput, both inheriting directly from TextInput. Here are the two class rules:
# NameInput inherits from TextInput
<NameInput@TextInput>:
multiline: False
size_hint: None, None
height: 30
width: 400
# NumInput inherits from TextInput
<NumInput@TextInput>:
multiline: False
size_hint: None, None
height: 30
width: 250
Now the code will be simplified to:
NameInput:
and
NumInput:
respectively.
If we replace all the occurrences of text inputs in the code, the kv file will look like so:
# File name: settings.kv
# RegularLabel inherits from Label.
<RegularLabel@Label>:
text_size: self.size
halign: 'left'
valign: 'center'
# TitleLabel inherits from RegularLabel.
<TitleLabel@RegularLabel>:
font_size: 20
size_hint: (1, None)
height: 30
# Regular80x30Label inherits from RegularLabel.
<Regular80x30Label@RegularLabel>:
size_hint: None, None
width: 80
height: 30
# DollarLabel inherits from Regular80x30Label.
<DollarLabel@Regular80x30Label>:
text: "$"
width: 20
# NameInput inherits from TextInput
<NameInput@TextInput>:
multiline: False
size_hint: None, None
height: 30
width: 400
# NumInput inherits from TextInput
<NumInput@TextInput>:
multiline: False
size_hint: None, None
height: 30
width: 250
<SettingsScreen>:
orientation: 'vertical'
padding: 10
spacing: 10
### SETTINGS LABEL ###
TitleLabel:
text: 'Settings'
font_size: 28
### THE PLAYERS ###
BoxLayout:
orientation: 'vertical'
padding: 10
spacing: 10
# Title
TitleLabel:
text: 'The Players'
font_size: 20
# Radiobuttons
BoxLayout:
size_hint: (.4, None)
height: 50
# 1 player
BoxLayout:
CheckBox:
group: 'players'
size_hint: (.5, 1)
RegularLabel:
text: '1 player'
# 2 players
BoxLayout:
CheckBox:
group: 'players'
size_hint: (.5, 1)
RegularLabel:
text: '2 players'
# 3 players
BoxLayout:
CheckBox:
group: 'players'
size_hint: (.5, 1)
RegularLabel:
text: '3 players'
# 4 players
BoxLayout:
CheckBox:
group: 'players'
size_hint: (.5, 1)
RegularLabel:
text: '4 players'
# Player name and initial money setup
BoxLayout:
orientation: 'vertical'
# the headers row
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 80
# name header
RegularLabel:
text: "Name"
size_hint_x: None
width: 700
# money header
RegularLabel:
text: "Initial Money"
# the players rows
# player 1
BoxLayout:
Regular80x30Label:
text: 'Player 1'
NameInput:
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 280
DollarLabel:
NumInput:
# player 2
BoxLayout:
Regular80x30Label:
text: 'Player 2'
NameInput:
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 280
DollarLabel:
NumInput:
# player 3
BoxLayout:
Regular80x30Label:
text: 'Player 3'
NameInput:
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 280
DollarLabel:
NumInput:
# player 4
BoxLayout:
Regular80x30Label:
text: 'Player 4'
NameInput:
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 280
DollarLabel:
NumInput:
### ENDING CONDITIONS ###
BoxLayout:
orientation: 'vertical'
size_hint: (1, .4)
padding: 10
spacing: 10
# title label
TitleLabel:
text: "Ending Conditions"
# radio buttons
GridLayout:
rows: 3
spacing: 10
# option 1: money
CheckBox:
group: 'conditions'
size_hint_x: .05
RegularLabel:
text: "The game is over when there is only one player with any money left."
# option 2: races
CheckBox:
group: 'conditions'
size_hint_x: .05
BoxLayout:
RegularLabel:
text: "The game is over not later than after a given number of races."
NumInput:
# option 3: time
CheckBox:
group: 'conditions'
size_hint_x: .05
BoxLayout:
RegularLabel:
text: "The game is over not later than the total racing time has elapsed."
NumInput:
### READY BUTTON ###
Button:
text: 'Ready'
size_hint: (None, None)
size: 200, 40
pos_hint: {'center_x': 0.5}
Now we reduced the code from about 270 to about 240 lines of code.
Custom Radio Buttons
Another pieces of repetitive code are the two radio button groups. There are radio buttons where you can choose the number of players in the Players area and radio buttons which you can use to choose an ending condition. As you know, radio buttons are just check boxes that all have the group property set to the same value.
Let’s have a look at the radio buttons as they are right now. Here’s the Players radio button:
CheckBox:
group: 'players'
size_hint: (.5, 1)
and here’s the Ending Conditions radio button:
CheckBox:
group: 'conditions'
size_hint_x: .05
There are four Players radio buttons and three Ending Conditions radio buttons. Let’s create custom radio buttons that inherit from CheckBox. Here are the two class rules:
# PlayerRadioButton and ConditionRadioButton inherit from CheckBox.
<PlayerRadioButton>:
group: 'players'
size_hint: (.5, 1)
<ConditionRadioButton>:
group: 'conditions'
size_hint_x: .05
Now we can use the new classes in code:
PlayerRadioButton:
and
ConditionRadioButton:
Here’s the full kv code:
# File name: settings.kv
# RegularLabel inherits from Label.
<RegularLabel@Label>:
text_size: self.size
halign: 'left'
valign: 'center'
# TitleLabel inherits from RegularLabel.
<TitleLabel@RegularLabel>:
font_size: 20
size_hint: (1, None)
height: 30
# Regular80x30Label inherits from RegularLabel.
<Regular80x30Label@RegularLabel>:
size_hint: None, None
width: 80
height: 30
# DollarLabel inherits from Regular80x30Label.
<DollarLabel@Regular80x30Label>:
text: "$"
width: 20
# NameInput inherits from TextInput
<NameInput@TextInput>:
multiline: False
size_hint: None, None
height: 30
width: 400
# NumInput inherits from TextInput
<NumInput@TextInput>:
multiline: False
size_hint: None, None
height: 30
width: 250
# PlayerRadioButton and ConditionRadioButton inherit from CheckBox.
<PlayerRadioButton@CheckBox>:
group: 'players'
size_hint: (.5, 1)
<ConditionRadioButton@CheckBox>:
group: 'conditions'
size_hint_x: .05
<SettingsScreen>:
orientation: 'vertical'
padding: 10
spacing: 10
### SETTINGS LABEL ###
TitleLabel:
text: 'Settings'
font_size: 28
### THE PLAYERS ###
BoxLayout:
orientation: 'vertical'
padding: 10
spacing: 10
# Title
TitleLabel:
text: 'The Players'
font_size: 20
# Radiobuttons
BoxLayout:
size_hint: (.4, None)
height: 50
# 1 player
BoxLayout:
PlayerRadioButton:
RegularLabel:
text: '1 player'
# 2 players
BoxLayout:
PlayerRadioButton:
RegularLabel:
text: '2 players'
# 3 players
BoxLayout:
PlayerRadioButton:
RegularLabel:
text: '3 players'
# 4 players
BoxLayout:
PlayerRadioButton:
RegularLabel:
text: '4 players'
# Player name and initial money setup
BoxLayout:
orientation: 'vertical'
# the headers row
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 80
# name header
RegularLabel:
text: "Name"
size_hint_x: None
width: 700
# money header
RegularLabel:
text: "Initial Money"
# the players rows
# player 1
BoxLayout:
Regular80x30Label:
text: 'Player 1'
NameInput:
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 280
DollarLabel:
NumInput:
# player 2
BoxLayout:
Regular80x30Label:
text: 'Player 2'
NameInput:
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 280
DollarLabel:
NumInput:
# player 3
BoxLayout:
Regular80x30Label:
text: 'Player 3'
NameInput:
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 280
DollarLabel:
NumInput:
# player 4
BoxLayout:
Regular80x30Label:
text: 'Player 4'
NameInput:
BoxLayout:
RegularLabel:
text: ""
size_hint_x: None
width: 280
DollarLabel:
NumInput:
### ENDING CONDITIONS ###
BoxLayout:
orientation: 'vertical'
size_hint: (1, .4)
padding: 10
spacing: 10
# title label
TitleLabel:
text: "Ending Conditions"
# radio buttons
GridLayout:
rows: 3
spacing: 10
# option 1: money
ConditionRadioButton:
RegularLabel:
text: "The game is over when there is only one player with any money left."
# option 2: races
ConditionRadioButton:
BoxLayout:
RegularLabel:
text: "The game is over not later than after a given number of races."
NumInput:
# option 3: time
ConditionRadioButton:
BoxLayout:
RegularLabel:
text: "The game is over not later than the total racing time has elapsed."
NumInput:
### READY BUTTON ###
Button:
text: 'Ready'
size_hint: (None, None)
size: 200, 40
pos_hint: {'center_x': 0.5}
This time the code didn’t get shorter, it’s still about 240 lines of code, because although the code was simplified, we added the class rules at the beginning, so the overall number of lines is more or less the same. But still, it was worth doing because we got rid of the code repetitiveness.
If you run the program now, after making all those changes, you should see the same window as before. I’m going to wrap it up now, but I’ll come back to the Settings screen and simplify it even more when we cover Kivy properties and ids. So, if you still can see some repetitiveness, don’t worry about that, we’ll fix that soon.
In the next part we’ll build the screen where we’re going to spend most of the time during the game, the Race screen.