In the previous part of the series we created the Race screen. I also mentioned that the Bets and Results screens will be injected into the Race screen in the final version of the program, but for now let’s create them as independent apps so that we can easily test them. So, in this part let’s focus on the Bets screen and in the next part we’ll create the Results screen.
When we were starting with some initial code in part 17, we left the bets.py and bets.kv files empty. So now we have to start from scratch.
First let’s have a look at the final version of the Bets screen:
So, what do we have here:
1) The Title Label – it reads Bets
2) The Player Bets – they are pretty complex
3) The Go Button – this is just a simple widget
So, the layout I think would take care of such a hierarchy well is a vertical BoxLayout.
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…
The root Widget of the Bets Screen
Let’s define the BetsScreen class in the Python file then. It should inherit from BoxLayout. Here’s the Python file:
# File name: bets.py
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class BetsScreen(BoxLayout):
pass
class BetsApp(App):
def build(self):
return BetsScreen()
if __name__ == '__main__':
BetsApp().run()
As you can see, the code is pretty much the same as in the previous Python files, for example when we were creating the Race screen. Naturally, the names of the root widget class and the name of the app are different.
Now that we have the BetsScreen class defined, let’s use it as the root widget in the kv file. In its basic form the kv file looks like this:
# File name: bets.kv
<BetsScreen>:
orientation: 'vertical'
### TITLE LABEL ###
### PLAYER BETS ###
### GO BUTTON ###
And now we can have a look at each area one by one. Or maybe rather let’s handle the first and last areas right away, because they are very simple and straightforward, and then let’s discuss the Player Bets area in more detail.
The Title Label and Go Button Areas
For the Title Label we’ll use the BoldLabel that we defined before. It inherits from RegularLabel, which itself inherits from Label. We need to add the appropriate class rules above the root widget. As mentioned before, all class rules that are shared by more than one screen will eventually be moved to a separate file, but for now let’s just add them to the bets.kv file.
So, the kv file at this point looks like this:
# File name: bets.kv
### CLASS RULES ###
<RegularLabel@Label>:
text_size: self.size
halign: 'left'
valign: 'center'
<BoldLabel@RegularLabel>:
bold: True
<BetsScreen>:
orientation: 'vertical'
padding: 10
spacing: 10
### TITLE LABEL ###
BoldLabel:
text: "Bets"
size_hint: (1, None)
height: 30
### PLAYER BETS ###
# just a placeholder for now
Label:
text: 'PLAYER BETS'
### GO BUTTON ###
# Let's make the button look the same as in the Settings screen.
# Only the text should be different.
Button:
text: 'Go'
size_hint: (None, None)
size: 200, 40
pos_hint: {'center_x': 0.5}
As you can see, I added some padding and spacing to the root widget. If you now run the app, you’ll get this:
The Player Bets Area
And now let’s handle the middle part of the screen, the Player Bets area. Here’s the picture again:
Here you can see two players only, because that’s what we set in the Settings screen, but there may be up to four players. Now, each player occupies one row. It contains some labels, a text input, a slider and four radio buttons with labels. For this area I’m going to use a vertical BoxLayout for the four rows (as you can see, some of them may be invisible, which we’ll take care of a bit later) and for each row I’ll use a horizontal BoxLayout. The code is pretty long, but there’s nothing new.
We have to add some class rules. As for the radio buttons we’ll add the PlayerSlugButton class. There will be a separate group set for each player because we want to be able to select one slug for each player. If we put all the radio buttons in one group, it would be only possible to select one slug for all the players altogether.
One more thing is the BetInput class. It will be used for the players’ bet amounts and will inherit from NumInput, which inherits from TextInput. We defined NumInput in the settings.kv file, so let’s just copy the class rule here and add the BetInput class. The BetInput will differ by width and the y-position.
As you can see in the picture above, there is a label with the dollar sign on it. We could use the DollarLabel class defined in the settings.kv screen, but there it inherits from Regular80x30Label class, in which the width and height properties are set to 80 and 30 respectively. We could overwrite these two properties, but I decided to take a simpler approach and just use a RegularLabel with the text property set to ‘$’.
Here’s the whole bet.kv file:
# File name: bets.kv
### CLASS RULES ###
<RegularLabel@Label>:
text_size: self.size
halign: 'left'
valign: 'center'
<BoldLabel@RegularLabel>:
bold: True
# PlayerSlugButton inherits from CheckBox.
<PlayerSlugButton@CheckBox>:
size_hint: (.5, 1)
# NumInput inherits from TextInput
<NumInput@TextInput>:
multiline: False
size_hint: None, None
height: 30
width: 250
# BetInput inherits from NumInput
<BetInput@NumInput>:
width: 120
pos_hint: {'center_y': .5}
<BetsScreen>:
orientation: 'vertical'
padding: 10
spacing: 10
### TITLE LABEL ###
BoldLabel:
text: "Bets"
size_hint: (1, None)
height: 30
### PLAYER BETS ###
BoxLayout:
orientation: 'vertical'
# player 1
BoxLayout:
spacing: 10
RegularLabel:
text: 'Player 1'
RegularLabel:
text: 'bets'
size_hint: (.4, 1)
BoxLayout:
spacing: 5
RegularLabel:
text: '$'
# In the RegularLabel class the horizontal alignment is set to 'left',
# but can be easily overwritten here.
halign: 'right'
BetInput:
# just an arbitrary number for now
text: '1000'
Slider:
# The min and max values will be for now set to 1 and 1000 respectively.
min: 1
max: 1000
# value will be set to 1000 for now.
value: 1000
# The slider should increment and decrement by 1.
step: 1
RegularLabel:
text: 'on'
size_hint: (.3, 1)
BoxLayout:
PlayerSlugButton:
group: 'player1'
RegularLabel:
text: 'Speedster'
BoxLayout:
PlayerSlugButton:
group: 'player1'
RegularLabel:
text: 'Trusty'
BoxLayout:
PlayerSlugButton:
group: 'player1'
RegularLabel:
text: 'Iffy'
BoxLayout:
PlayerSlugButton:
group: 'player1'
RegularLabel:
text: 'Slowpoke'
# player 2
BoxLayout:
spacing: 10
RegularLabel:
text: 'Player 2'
RegularLabel:
text: 'bets'
size_hint: (.4, 1)
BoxLayout:
spacing: 5
RegularLabel:
text: '$'
halign: 'right'
BetInput:
text: '1000'
Slider:
min: 1
max: 1000
value: 1000
step: 1
RegularLabel:
text: 'on'
size_hint: (.3, 1)
BoxLayout:
PlayerSlugButton:
group: 'player2'
RegularLabel:
text: 'Speedster'
BoxLayout:
PlayerSlugButton:
group: 'player2'
RegularLabel:
text: 'Trusty'
BoxLayout:
PlayerSlugButton:
group: 'player2'
RegularLabel:
text: 'Iffy'
BoxLayout:
PlayerSlugButton:
group: 'player2'
RegularLabel:
text: 'Slowpoke'
# player 3
BoxLayout:
spacing: 10
RegularLabel:
text: 'Player 3'
RegularLabel:
text: 'bets'
size_hint: (.4, 1)
BoxLayout:
spacing: 5
RegularLabel:
text: '$'
halign: 'right'
BetInput:
text: '1000'
Slider:
min: 1
max: 1000
value: 1000
step: 1
RegularLabel:
text: 'on'
size_hint: (.3, 1)
BoxLayout:
PlayerSlugButton:
group: 'player3'
RegularLabel:
text: 'Speedster'
BoxLayout:
PlayerSlugButton:
group: 'player3'
RegularLabel:
text: 'Trusty'
BoxLayout:
PlayerSlugButton:
group: 'player3'
RegularLabel:
text: 'Iffy'
BoxLayout:
PlayerSlugButton:
group: 'player3'
RegularLabel:
text: 'Slowpoke'
# player 4
BoxLayout:
spacing: 10
RegularLabel:
text: 'Player 4'
RegularLabel:
text: 'bets'
size_hint: (.4, 1)
BoxLayout:
spacing: 5
RegularLabel:
text: '$'
halign: 'right'
BetInput:
text: '1000'
Slider:
min: 1
max: 1000
value: 1000
step: 1
RegularLabel:
text: 'on'
size_hint: (.3, 1)
BoxLayout:
PlayerSlugButton:
group: 'player4'
RegularLabel:
text: 'Speedster'
BoxLayout:
PlayerSlugButton:
group: 'player4'
RegularLabel:
text: 'Trusty'
BoxLayout:
PlayerSlugButton:
group: 'player4'
RegularLabel:
text: 'Iffy'
BoxLayout:
PlayerSlugButton:
group: 'player4'
RegularLabel:
text: 'Slowpoke'
### GO BUTTON ###
Button:
text: 'Go'
size_hint: (None, None)
size: 200, 40
pos_hint: {'center_x': 0.5}
And this is what you will get if you now run the bets.py file and then resize the window:
This is more or less what we were aiming at, at least as far as the visual representation is concerned. Naturally, here we can see all four players, because their visibility will be taken care of later in the series. In the next part we’ll create the Results screen, which will replace the Bets screen after each race finishes. As I said before, in the final version both the Bets screen and the Results screen will be shown inside the Race screen which we already created.