October 15, 2024

Widgets in Kivy: let’s get that UI functional

Spread the love

In this article, some of the widgets offered in Kivy. I will talk about how to use them, how to customize them, and also go over some of the advanced functionalities of those widgets. We will create a very basic application so that we can implement our learning and see it in practice.

classic button

Clicking a button:

  • In the Kv file where we have defined the widget, we can use the property on_press and pass in the python function which is defined in our python file.
  • Make sure when you pass in the python function, you run it and not simply point towards it.
  • Also use root. before the function name to specify the location of the python function.
--- Python File
from kivy.app import App
from kivy.uix.gridlayout import GridLayout

# Defining Grid Layout
class GridLayoutExample(GridLayout):
    def button_press_handler(self):
        print('Button Clicked')

# Defining Kivy App
class TheLabApp(App):
    pass

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

--- Kv File (File Name: thelab.kv)
#:kivy 1.0
GridLayoutExample:

<GridLayoutExample>:
    cols: 2
    Button:
        text: 'Count'
        on_press: root.button_press_handler()
    Label:
        text: 'Count value'

Let’s walk through the code:

  • In the python file,
    • We define a class for our app and inherit App from kivy.app.
    • Then we start the app using className.App().run()
    • For the UI part, we define a class GridLayoutExample and inherit GridLayout from kivy.uix.gridlayout.
    • Inside that we define the python funciton which we want to execute whenever the button is clicked.
  • In the Kv file,
    • Make sure that the file name is lower case app name without “App”
    • We define GridLayoutExample followed by a : ( GridLayoutExample: ), which defines our main window.
    • Then we start adding widgets to the GridLayoutExample, so we use <GridLayoutExample> as our parent widget.
    • Since we are working with grid layout, we need to define either row or columns, so we start by defining cols=2. This will cause our layout to have 2 columns.
    • We then define a button with ‘Count’ as text value ( text: “Count” )and call the python fucntion, defined in our python file, to on_press property ( on_press: root.button_press_handler() )
    • Please note: we can pass self inside the root.button_press_handler(self), this passes the widget object which can be used by our python funciton for various funcitonalities. More on this a little later in the ToggleButton section. But just wanted to point this out here, so that we know that Button also allows this functionality.
  • So now whenever the button is clicked, “Button Clicked” is printed in the console.

Label Widget

Customizing the label widget

  • Updating the text dynamically:
    • Instead of a string value for the text property, we can use the StringProperty method from kivy.properties
    • Then we can use the python function to update the value for the label text.
  • Using custom font:
    • We can import our custom font using the font_name property and pass in the path of the font file.
  • Updating text size:
    • We can set a particular font size using font_size property
  • Updating text color:
    • For changing the color, we will use color property.
    • Color property takes in 4 parameters seperated by commas, color: red, green, blue, alpha values

Applying what we learned so far

Let’s use the above knowledge and create a simple GUI which

  • Contains a button and a label in two columns
  • When we click the button, the label should count from 1 and increase with every click
  • Use a custom font and a custom size for the label text
  • Update the color for the label text
--- Python File
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.properties import StringProperty

# Defining Grid Layout
class GridLayoutExample(GridLayout):
    label_text = StringProperty('1')
    count = 1

    def button_press_handler(self):
        self.count += 1
        self.label_text = str(self.count)

# Defining Kivy App
class TheLabApp(App):
    pass

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

--- Kv File (thelab.kv)
#:kivy 1.0
GridLayoutExample:

<GridLayoutExample>:
    cols: 2
    Button:
        text: 'Count'
        on_press: root.button_press_handler()
    Label:
        text: root.label_text
        font_name: 'fonts/Lcd.ttf'
        font_size: '100dp'
        color: 1, 0, 1, 1

Let’s walk through the code:

  • The UI elements is similar to what we already discussed, so I won’t be going over that here.
  • For dynamically updating the label text
    • We import StringProperty from kivi.properties
    • Using that we define a variable label_text and use that variable as root.label_text within the Kv file to set the text value for the label
    • We then define a function button_press_handler, such as it increments a count variable and sets the label_text as the new value. This results in updating the actual label text.
    • We call that function inside the Button widget in the Kv file using root.button_press_handler()
  • Customizing the font and size for the label
    • For font, we use font_name and pass the path of the font file.
    • For size, we use font_size property and set the desired value.

Toggle Button

  • It’s like a button widget with a state of On and Off.
  • The actual states are: Normal (Off) and Down (On)
  • In order to manage the interaction we use on_state
  • This widget also returns an object which has various properties like text, state, etc.

Applying what we learned so far

Let’s understand the application of a toggle button by implementing it in our GUI:

  • Update the GUI to have 3 columns instead of 2
  • Add a toggle button with custom size in the first column
  • Add a functionality such that when the toggle button is activated we can no longer press on our Count button. And the Count button is functional back again when the toggle button is deactivated.
  • Also, as a bonus point, update the Count button to be disabled (not able to click) when the toggle button in activated.
--- Python File
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.properties import StringProperty
from kivy.properties import BooleanProperty
from kivy.uix.button import Button

# Defining Grid Layout
class GridLayoutExample(GridLayout):
    label_text = StringProperty('1')
    count_enabled = BooleanProperty(True)
    count = 1

    def button_press_handler(self):
        if self.count_enabled:
            self.count += 1
            self.label_text = str(self.count)
            
    def toggle_button_handler(self, widget):
        if widget.state == 'down':
            widget.text = 'Enable Counter'
            self.count_enabled = False
        else:
            widget.text = 'Disable Counter'
            self.count_enabled = True

# Defining Kivy App
class TheLabApp(App):
    pass

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

-- Kv File (File Name: thelab.kv)
#:kivy 1.0
GridLayoutExample:

<GridLayoutExample>:
    cols: 3

    ToggleButton:
        text: 'Disable Counter'
        on_state: root.toggle_button_handler(self)
        size_hint_x: None
        width: '200dp'

    Button:
        text: 'Count'
        on_press: root.button_press_handler()
        disabled: not(root.count_enabled)
    
    Label:
        text: root.label_text
        font_name: 'fonts/Lcd.ttf'
        font_size: '100dp'
        color: 1, 0, 1, 1
        pos_hint: {'center_x': .5}

Let’s walk through the Kv File:

  • First we updated our grid layout to have 3 columns, using cols: 3
  • Next, we added a toggle button, using ToggleButton and set it’s property as:
    • text: ‘Disable Counter’, this is the default text
    • on_state: root.toggle_button_handler(self), a python funciton which handles action when the toggle button is presesd. Notice that we are passing self to the function. This self represents the widget object, which can be used to get the state of the toggle button and also update the text value.
    • We set a custom width by setting the size_hint_x to None and then setting the desired width using width property.
  • For the Button widget:
    • We add a new property, disabled and set it to a inverse root variable count_element becuase the count_element is set to True by default and we want to set the disabled property as False so that the button is not disabled by default. (Hope this isn’t that confusing)

Let’s walk through the python file:

  • We added the toggle_button_handler(self, widget) funciton for the toggle button.
  • Notice that we are accepting widget along with self as an argument. This is becuase in the Kv file, we are passing self (which is the widget object) to the funciton, so we need to accept that in the python file.
  • We then use that widget object to get the current state of the toggle button by using .state property
    • current state -> normal, if the toggle button is not activated
    • current state -> down, if the toggle button is activated
  • We also use .text property for updating the text value of the toggle button
  • Now for the actual functionality
    • We define a variable count_enabled and set it True. This will help us determine if the count functionality of the button is active or not.
    • We toggle this variable depending on the status of the toggle button, hence controlling if we are able to increment the count or not.
  • Enabling and disabling the count button
    • We updated the count_enabled variable to a BooleanProperty, by importing BooleanProperty from kivy.properties.
    • The reason of updating the count_enabled variable to a BooleanProperty is so that it can be used in the Kv file.

Hopefully, this article gives you a better understanding of how to use Button, Label, and Toggle Button widgets in kivy. Please note, I am no professional by any means, I am writing these articles to help me understand a library and also help someone like me along the way.

Switch

  • It’s very much similar to a toggle button. In order to set the functionality to it, we use on_active (instead of on_state for toggle button)
  • It also returns the widget object and the status of the widget can be obtained by using ” .active
  • widget.active returns a boolean value, True if the switch is On and False if it’s Off
  • Some distinct properties:
    • id, it is the widget object which can be used directly within another widgets
    • active, sets the inital active status
  • Getting the value:
    • You could either use the functional way of getting the active status, ie. create a handler function, return the widget and get value from that widget object
    • Or, you can use id property. Let’s say we set id: switch_object then we can get the current active status of the slider by simply using slider_object.active within any other widget directly
    • The default value which is returned is a boolean value

Slider

  • It provides a slider with set values, the slider can be use to set a particluar value based on the slider position.
  • Some properties:
    • id, it is the widget object which can be used directly within another widgets
    • min, to set the minimum value
    • max, to set the maximum value
    • default, to set the default value
    • on_value, for adding a python function. The function returns the widget object, and the current value of slider can be accessed using ” .value ” property. Please note, tt returns a float value
    • orientation, to set the orientation of the slider
  • Getting the value:
    • You could either use the functional way of getting the value, ie. create a handler function, return the widget and get value from that widget object
    • Or, you can use id property. Let’s say we set id: slider_object then we can get the current value of the slider by simply using slider_object.value within any other widget directly

Applying what we learned so far

The purpose of this exercise is:

  • Enable / Disable the slider using the switch button
    • Switch should be activated by default
    • Only use Kv file
  • Add a label widget which displays the current value of the slider as we change the slider
    • Only use Kv file
# We don't need to update our python file as we will be using " id " property to get the values and set properties
#:kivy 1.0
GridLayoutExample:

<GridLayoutExample>:
    cols: 3
    
    Switch:
        id: switch_object
        active: True
        size_hint_x: None
        width: '200dp'
        # on_active: root.switch_handler(self)
    
    Slider:
        id: slider_object
        disabled: not switch_object.active
        min: 0
        max: 100
        orientation: 'vertical'
    
    Label:
        text: str(int(slider_object.value))
        font_name: 'fonts/Lcd.ttf'
        font_size: '100dp'
        color: 1, 0, 1, 1
        pos_hint: {'center_x': .5}

Progress Bar

  • A widget to show some kind of progress.
  • It can be used by using ProgressBar
  • Some properties:
    • max, sets the max value
    • value, to set the value of the bar
  • Let’s say in the above example we want to add a progress bar which is directly linked to the slider. The progress bar changes depending on the slider, then we can set the value property using the id of the slider such as, value: int(slider_object.value)

Text Input

  • It’s a widget useful for adding multiline text
  • It can be used by using TextInput
  • Some properties:
    • id, returns a widget object
    • text, sets the default text
    • multiline, by default it’s True, it allows the user to enter data in multiple lines
    • on_text_validate, let’s us add a function which is triggered when the text inside the widget is validated (when the user hits enter key)

Images

  • This widget can be used to display an image on the screen
  • The maximum size is fixed and set to the actual size of the image. When you reduce the screen size than the actual size of the image, the image does keep it’s aspect ratio and reduces along with the image.
  • Some properties:
    • source, path of the image you want to display
    • allow_stretch, boolean value, allows the image to stretch based on the available space
    • keep_ratio, boolean value, allows the image to disregard its aspect ratio. It can only be used if the allow_strech property is set to True

Hopefully, the above article gives you a better understanding and a starting point for the different types of widgets that are available in Kivy and how to use them in a practical application.


Spread the love

Leave a Reply

Your email address will not be published. Required fields are marked *