Kivy For The Non Computer Scientist – A Compendium Of Blog Posts To Date.

 

kivy

Earlier today I post my 18th blog post relating to what I have learned about Kivy. I thought it would be good at this time to provide a compendium of them in one place.

Here they are:

Part 1: Making It Simple

Part 2: Concepts To Get A Handle On

Part 3: Kivy’s Hello, World! Examined

Part 4: A Little About Kivy’s Screen Layouts

Part 5: Making A Kivy Button Do Something

Part 6: Code Cleanup And Kivy Convention

Part 7: Simple Checkbox Code

Part 8: Adding A Checkbox Label

Part 9: Dynamic Checkbox Labels

Part 10: KV Language

Part 11: Using KV Language To Set Widget Text Size, Text Position And Text And Button Colours

Part 12 – KV Language – Switching Between Kivy GUI Screens

Part 13: Creating More Complex Kivy GUI’s Using Nesting And KV Language

Part 14: Button Presses That Update Labels And Change Screens Using KV Language.

Part 15: Interacting With Python

Part 16: Reading Text From Kivy Buttons Created In KV Language For Use In Python Code.

Part 17: Making Natural Looking GUI’s Using Kivy’s Float Layout.

Part 18: How To Create Multi-screen Applications Using KV Language Then Update Individual Screens.

 

Advertisements

Kivy For The Non Computer Scientist – Part 18: How To Create Multi-screen Applications Using KV Language Then Update Individual Screens.

Long title! If you’ve been following the progress of my efforts to convert Convergence Jukebox to a Kivy based multi-screen application, I recently reached the point where I had completed the basic single screen version. It was now time to start on the multi-screen application. After my first attempt I ran into some major problems.

They were;

  1. Trying to build and code the screen management was clumsy using python. I realized it was time to “suck it up buttercup” and learn how to build the screen management in kv language.
  2. In trying to update the screen built in Part 17: Making Natural Looking GUI’s Using Kivy’s Float Layout of this series I could not figure out how to update the text on the various buttons and labels that was on the screen once it was placed in a multi-screen app. Because Kivy’s documentation is so scattered I went to StackOverflow.com and the discussions that formed this blog post can be found at;

In his post the kv language code will generate a four screen app, that will push through the four screens that have different text indicating their screen number. When completed the first screen will be re-pushed onto the screen with it’s text changed to indicate it’s screen five.

The app will look as follows as shown on this YouTube video;

The complete working code is as follows;

import kivy
kivy.require('1.10.0')
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock # Imports Kivys clock object.
from kivy.uix.screenmanager import Screen

class FirstScreen(Screen): # Defines FirstScreen instance as a screen widget.
    pass

class SecondScreen(Screen): # Defines SecondScreen instance as a screen widget.
    pass

class ThirdScreen(Screen):# Defines ThirdScreen instance as a screen widget.
    pass

class FourthScreen(Screen):# Defines FourthScreen instance as a screen widget.
    pass

root_widget = Builder.load_string("""
ScreenManager:
    FirstScreen:
    SecondScreen:
    ThirdScreen:
    FourthScreen:
<FirstScreen>:
    _first_screen_text_: first_screen
    name: 'my_first_screen'
    Label:
        id: first_screen
        text: "Hi I'm The First Screen"
<SecondScreen>:
    _second_screen_text_: second_screen
    name: 'my_second_screen'
    Label:
        id: second_screen
        text: "Hi I'm The Second Screen"
<ThirdScreen>:
    _third_screen_text_: third_screen
    name: 'my_third_screen'
    Label:
        id: third_screen
        text: "Hi I'm The Third Screen"
<FourthScreen>:
    _fourth_screen_: fourth_screen
    name: 'my_fourth_screen'
    Label:
        id: fourth_screen
        text: "Hi I'm The Fourth Screen"
""")

class SwitchingScreenApp(App):
    def build(self):
        Clock.schedule_once(self.screen_switch_one, 2) # clock callback for the first screen
        Clock.schedule_once(self.screen_switch_two, 4) # clock callback for the second screen
        Clock.schedule_once(self.screen_switch_three, 6) # clock callback for the third screen
        Clock.schedule_once(self.screen_switch_four, 8) # clock callback for the fourth screen
        Clock.schedule_once(self.text_replace_screen_one, 9)# clock callback to change text the first screen
        Clock.schedule_once(self.screen_switch_one, 10) # clock callback for the first screen
        return root_widget

    def text_replace_screen_one(a,b):
        root_widget.get_screen('my_first_screen')._first_screen_text_.text = "Hi I'm The Fifth Screen" # code to change text on specific screen and widget.

    def screen_switch_one(a, b):
        root_widget.current = 'my_first_screen' # switches screen using Screen Managers current method and desired screens name.

    def screen_switch_two(a, b):
        root_widget.current = 'my_second_screen' # switches screen using Screen Managers current method and desired screens name.

    def screen_switch_three(a, b):
        root_widget.current = 'my_third_screen' # switches screen using Screen Managers current method and desired screens name.

    def screen_switch_four(a, b):
        root_widget.current = 'my_fourth_screen' # switches screen using Screen Managers current method and desired screens name.

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

Setting Up The Multi-screen In KV Language

It’s lines 20 thru 47 in the code above that contains the kv language that builds our multi-screen base. Let’s go through the build line by line;

Line 21 – Invokes the Screen Manager. The screen manager is a widget dedicated to managing multiple screens for your application. Notice the format of the line of code… It’s not indented or enclosed in brackets. In kv language, which is a series of rules, this is how on declares the class of your root widget. In kv language you can only have one root rule (or widget). In this case we’ve called the ScreenManager class.

Lines 22 thru 25 – These lines both create and name the multiple screens that are found in this app. Notice the format of each line of code… This time they are indented. In kv language each indented line in this manner creates a child of the ScreenManager class. So in this case each line of code advises that a child (or an instance) will be created from this class and its name is provided.

Line 26 – Invokes the graphical instance of the first screen of our app. Note the format of this rule… The text is wrapped with brackets and followed with a colon. In kv language this is known as a class rule. Text in this format defines how instances of a class will be graphically represented.  In this case it’s the graphical representation of the apps first screen.

Line 27 – This is probably the most poorly documented rule in Kivy. This line provides access from outside the instance (or widget) to a screen property by Python. Without it one will never be able to access the screens properties from outside of Kivy.

To understand this better look at the relationship by observing Line 30. On this line the variable _first_screen_text_ is assigned the variable first_text. Now look at Line 30. Line 30 is the is the id of the screens Label widget. With this link in place one can now access the first screens label text in python via the _first_screen_text_ variable. You can look ahead and see how that variable is referenced and the text is changed on Line 63 of the code.

Also notice that I’ve added underscores to the beginning and end of the _first_screen_text_ variable’s name. This was done to remind me that this is my reference to the screens property from Python. This is not a hard and fast requirement, but as a program grows in complexity it’s useful to understand that this is the properties reference and exactly what property it is.

I’ve done my best to explain this rule. The documentation is found here. Hopefully you can make better sense of it than I can.

Line 28 – Sets the rule for the name of the screen that’s used by Kivys Screen Manager. The Name is used later in the code to select the screen to be displayed ( Lines 66, 69, 72, and 75) using its current property and the get a specific screen (Line 63) to change the first screens text. You’ll find the documentation for these methods in the Screen Managers api.

Line 29 – Declares that a label widget will be displayed on the screen.

Line 30 – This indented line provides the id for the label widget. It’s referenced in Line 27 as discussed above.

Line 31 – Is the text property of the label that will be displayed on the first screen.

Lines 32 thru 37 – Defines the kv language rules for the second screen.

Lines 38 thru 43 – Defines the kv language rules for the third screen.

Lines 44 thru 49 – Defines the kv language rules for the fourth screen.

Python Code

Line 8 – Defines that the FirstScreen instance created in kv language is a screen widget.

Line 11 – Defines that the SecondScreen instance created in kv language is a screen widget.

Line 14 – Defines that the ThirdScreen instance created in kv language is a screen widget.

Line 17 – Defines that the FourthScreen instance created in kv language is a screen widget.

Kivy’s Clock Object

In this application Kivy’s clock object is used to automatically switch between screens. The clock object allows one to schedule events at a specific time. The clock uses delta time as its time property. Delta time is the time between frames and is expressed in seconds. The clock calls functions (callbacks). Kivy’s clock does not execute individual lines of code directly but will execute an anonymous function or lambda.

In this application the clock object code is instantiated during the build process and each callback has it’s own line of code. So the clock object code is found as follows;

Line 5 – Imports Kivy’s clock object.

Line 54Kivy clock object code that calls for the first screen to be displayed after two seconds.

Line 55 – Kivy clock object code that calls for the second screen to be displayed at four seconds.

Line 56 – Kivy clock object code that calls for the third screen to be displayed at six seconds.

Line 57 – Kivy clock object code that calls for the fourth screen to be displayed at eight seconds.

Line 58 – Kivy clock object code that calls for the text on the first screen to be changed at nine seconds.

Line 59 – Kivy clock object code that calls for the first screen to be displayed (with the updated text) after ten seconds.

Lines 66, 69, 72, and 75 – Are the Kivy Clock callback(s) code that use Kivy’s Screen Manager’s current method to display the appropriate screen. Note the screens are identified by their name property.

Line 63 – Contains the code that changes the text on the first screen. This is done in one line of code by first calling the Screen Managers get_screen() function with the appropriate screen name (in this case my_first_screen), then identifying the specific widget (_first_screen_text_ as coded on Line 27) and then changing the labels text property with the appropriate code.

I hope this post helps you in your quest to learn Kivy….

….brad….

 

Amanda Hogan Decoding Kivy

Amanda Hogan Explains Kivy Popups

Good Kivy Tutorial

Github Repository with follow along code: http://bit.ly/2ttDcjH

 

Kivy (Kind Of) pushMatrix and popMatrix Tutorial.

I was working with Kivy and having a hard time visualizing pushMatrix and popMatrix. Although this tutorial is using Javascript, he first 5 minutes is great for visualizing what pushMatrix and popMatrix do on a Kivy canvas.

Kivy For The Non Computer Scientist – Part 17: Making Natural Looking GUI’s Using Kivy’s Float Layout.

In this blogpost we’ll look at how one can create more natural looking GUI’s by employing a background graphic and Kivy’s float layout. The post will also provide complete code and a background graphic, that place buttons and labels in precise locations for a 720p Jukebox interface. The interface is from the open source Convergence Jukebox project. The interface will appear as follows;

converge

Some things to understand before proceeding.

  • The GUI shown above and the code provided require that the graphic be rendered at 720p.
    • Only at 720p will all of the labels and buttons to line up appropriately in this example.
    • Assuming your display can handle 720p the GUI will render to that resolution when the code is run.
  • Float Layouts have unique properties in that;
    • Kivy Buttons and Labels (widgets) can be placed anywhere on the GUI.
    • Each widget type can be given both common and unique properties when deployed on the GUI itself.

The code for the above GUI is as follows;


import kivy
kivy.require("1.9.1")  # Used to alert user if this code is run on an earlier version of Kivy.
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.core.window import Window  # Used to set Window to set window size and full screen

Window.fullscreen = False  # Does not force full screen
Window.size = (1280, 720)  # Sets 720p

Builder.load_string('''
<Label>: # Sets generic properties for Label instances. Can be overridden by changing properties in specific instance.
	color: 0,.7,0,1 # Sets Label generic text colour to green.
	font_size: 18 # Sets Label generic text font size to 18.
	valign: 'middle' # Sets Label generic text vertical alignment to middle.
	halign: 'left' # Sets Label generic text horizontal alignment to left.
	text_size: self.size # Forces text to be wrapped to fit Label size.
<Button>: # Sets generic properties for Button instances. Can be overridden by changing properties in specific instance.
	font_size: 18 # Sets Button generic font size to 18.
	color: 1,1,1,1 # Sets Button generic colour to white.
    bold: True # Sets Button generic text property to bold.
    background_normal: "" # Resets Button background default to plain.
    background_color: (0.0, 0.0, 0.0, 0.0) # Sets Button generic background colour to transparent.
    halign: 'center' # Sets Button generic horizontal alignment to center.
    valign: 'middle' # Sets Button generic vertical alignment to middle.
	text_size: self.size # Sets Button generic text to be wrapped to fit Button size.
	size_hint: .255, .0620 # Sets Button generic size.
<FloatLayout>:  # Creates a FloatLayout
    canvas.before:
        BorderImage: # Used to display background image.
            source: 'jukebox.png' # Background image filename.
            pos: self.pos # Positions image to take up 100% of layout.
            size: self.size # Positions image to take up 100% of layout.
	Label: # Creates an instance of Label on GUI. Properties below overide generic settings on this Label instance only.
	    id: sort_mode  # Identifies Label as sort_mode
	    text: "Sort Mode By Artist" # Text for this Label.
	    font_size: 38 # Overrides generic Label font size to 38 for this Label only.
	    halign: 'center' # Overrides generic Label horizontal alignment to center for this Label only.
	    size_hint: .3, 1 # Overrides generic Label size for this Label only.
		pos: 12,280 # Positions this label.
	Label: # Creates an instance of Label on GUI. Properties below overide generic settings on this Label instance only.
	    id: play_mode  # Identifies Label as sort_mode
	    text: "Mode: play_mode" # Text for this Label.
		pos: 40,245 # Positions this label.
	Label:
	    id: title_song
	    text: "Title: title_song"
		pos: 40,225
	Label:
	    id: title_artist
	    text: "Artist: title_artist"
		pos: 40,205
	Label:
	    id: title_year
	    text: "Year: 2017"
	    size_hint: 0.35, 1
		pos: 40,185
	Label:
	    id: title_length
	    text: "Length: title_length"
		pos: 135,185
	Label:
	    id: title_album
	    text: "Title: title_album"
		pos: 40,165
	Label:
	    id: sort_mode
	    text: "UPCOMING SELECTIONS"
	    font_size: 28
	    halign: 'center'
	    size_hint: .32, 1
		pos: 1,131
	Label:
	    id: selection_one
	    text: "selection_one"
		pos: 40,102
	Label:
	    id: selection_two
	    text: "selection_two"
		pos: 40,81
	Label:
	    id: selection_three
	    text: "selection_three"
		pos: 40,60
	Label:
	    id: selection_four
	    text: "selection_four"
		pos: 40,40
	Label:
	    id: selection_five
	    text: "selection_five"
		pos: 40,19
	Label:
	    id: selection_six
	    text: "selection_six"
		pos: 40,-1
	Label:
	    id: selection_seven
	    text: "selection_seven"
		pos: 40,-21
	Label:
	    id: selection_eight
	    text: "selection_eight"
		pos: 40,-41
	Label:
	    id: selection_nine
	    text: "selection_nine"
		pos: 40,-61
	Label:
	    id: selection_ten
	    text: "selection_ten"
		pos: 40,-81
	Label:
	    id: selection_eleven
	    text: "selection_eleven"
		pos: 40,-101
	Label:
	    id: selection_twelve
	    text: "selection_twelve"
		pos: 40,-121
	Label:
	    id: selection_thirteen
	    text: "selection_thirten"
		pos: 40,-141
	Label:
	    id: selection_fourteen
	    text: "selection_fourteen"
		pos: 40,-161
	Label:
	    id: selection_fifteen
	    text: "selection_fifteen"
		pos: 40,-181
	Label:
	    id: selection_sixteen
	    text: "selection_sixteen"
		pos: 40,-201
	Label:
	    id: credit_count
	    text: "CREDITS 0"
	    font_size: 34
	    halign: 'center'
	    size_hint: .3, 1
		pos: 12,-236
	Label:
	    text: "Twenty-Five Cents Per Selection"
	    halign: 'center'
	    size_hint: .3, 1
		pos: 12,-267
	Label:
	    id: selections_available
	    text: "selections_available"
	    halign: 'center'
	    size_hint: .3, 1
		pos: 12,-287
	Label:
	    id: jukebox_name
	    text: "Convergence Music System 2.0"
	    color: 0,0,0,1 # Sets text colour to black.
	    font_size: 38
	    bold: True
	    halign: 'center'
	    size_hint: .7, 1
		pos: 390,292
	Label:
	    id: song_name
	    text: "song_name"
	    color: 1,1,1,1 # Sets text colour to white.
	    font_size: 40
	    bold: True
	    halign: 'center'
	    size_hint: .7, 1
		pos: 390,230
	Label:
	    id: artist_name
	    text: "artist_name"
	    color: 1,1,1,1 # Sets text colour to white.
	    font_size: 40
	    bold: True
	    halign: 'center'
	    size_hint: .7, 1
		pos: 390,180
    Button: # Creates an instance of Button on GUI. Properties below overide generic settings on this Button instance only
	    id: song_0  # Identifies Button as song_0.
	    text: "song_0(Name)\\nsong_0(artist)" # Text for button includes line break.
		pos: 495,445 # Positions Button on GUI.
	Button:
	    id: song_1
	    text: "song_1(Name)\\nsong_1(artist)"
		pos: 495,390
	Button:
	    id: song_2
	    text: "song_2(Name)\\nsong_2(artist)"
		pos: 495,335
	Button:
	    id: song_3
	    text: "song_3(Name)\\nsong_3(artist)"
		pos: 495,280
	Button:
	    id: song_4
	    text: "song_4(Name)\\nsong_4(artist)"
		pos: 495,225
	Button:
	    id: song_5
	    text: "song_5(Name)\\nsong_5(artist)"
		pos: 495,170
	Button:
	    id: song_6
	    text: "song_6(Name)\\nsong_6(artist)"
		pos: 495,115
	Button:
	    id: song_7
	    text: "song_7(Name)\\nsong_7(artist)"
		pos: 495,60
	Button:
	    id: song_8
	    text: "song_8(Name)\\nsong_8(artist)"
		pos: 835,445
	Button:
	    id: song_9
	    text: "song_9(Name)\\nsong_9(artist)"
		pos: 835,390
	Button:
	    id: song_10
	    text: "song_10(Name)\\nsong_10(artist)"
		pos: 835,335
	Button:
	    id: song_11
	    text: "song_11(Name)\\nsong_11(artist)"
		pos: 835,280
	Button:
	    id: song_12
	    text: "song_12(Name)\\nsong_12(artist)"
		pos: 835,225
	Button:
	    id: song_13
	    text: "song_13(Name)\\nsong_13(artist)"
		pos: 835,170
	Button:
	    id: song_14
	    text: "song_14(Name)\\nsong_14(artist)"
		pos: 835,115
	Button:
	    id: song_15
	    text: "song_15(Name)\\nsong_15(artist)"
		pos: 835,60

''')

class RootWidget(FloatLayout):
    pass

class MainApp(App):
    def build(self):
        return RootWidget()

MainApp().run()

You’ll also need this graphic and ensure its named jukebox.png and it’s placed in the same directory as the above code;

jukebox

You can download this graphic by right mouse clicking and performing a Save As or by clicking on the link above.

Here are some of the new items you’ll find in the code;

  • Lines 12 and 18 – These lines establish generic properties for first the Label instances (line 12 and below) and then the Button instances (line 18 and below) when they are called.
    • In FloatLayouts these generic properties can be overridden by changing properties when a specific instance is established.
    • By setting up generic properties in this manner, the KV Language code is reduced significantly when instances are called.
      • In this app 45 instances of Buttons and Labels are created.
    • All lines involved in establishing the generic properties have comments as to what they do.
  • Line 23 – Code that sets Button generic background colour to transparent.
  • Lines 29 thru 33 – Code places and sets up GUI’s background image.
    • Comments provide insight into role each property plays
  • Lines 34 thru 40 – Code lays out first Label on Gui. Lines are commented so you know what function they play.
    • Any properties declared on these lines that match generic properties, override generic settings for this instance only.
  • Lines 39 and 40 – size_hint and pos properties work in concert with one another to set Label position. size_hint sets size of Label. pos positions top left corner of label.
    • Positioning is one of the hardest things to explain in a FloatLayout. I just kept changing both the size_hint and pos values until Labels lined up.
  • Lines 41 thru 44 – Code lays out second Label on Gui. Comments define what each line of code does.
  • Lines 45 thru 245 – Code for the remainder of Labels and Buttons on Gui following principles outlined above.
  • Lines 182 – 185 – Code for first Button placed on GUI.
  • Line 184 – Text for button using a line break.

To conclude the great thing about using a FloatLayout is the ability to place a widget with great accuracy on your Kivy GUI. As well, the use of a background image and transparent button overlays as performed in this example makes for a much more natural looking interface for your user.

In this case we have a layout that displays all of the widget’s object names. Based on what was presented in earlier blogposts in this series, the Buttons and Labels texts can be updated accordingly as well as callbacks added to buttons to provide the desired functionality.

Happy coding,

….brad….