A reference collection and overview of Kivy widgets for your Python GUI needs

Keno Leon
Keno Leon
Feb 18 · 7 min read

What, Why ?

Kivy in case you are not aware is one of a few GUI options for Python, other popular one’s being tkinter, pyQt and others.

I personally think Kivy has a great mix of features and open sourceness which gives it a bit of an edge for some applications, being fairly new to it myself I did struggle a bit getting started and figuring out if it was something I would need and would fit my project, so this post aims to serve as a complement to the documentation and showcase of the widgets that Kivy gives you out of the box.

⛔️ Note: If you need a crash course...http://inclem.net/pages/kivy-crash-course/And the Docs:https://kivy.org/doc/stable/gettingstarted/intro.html

One Widget, Two Widgets, Three Widgets.

👀 You can get all the source files here :https://github.com/KenoLeon/KivyMenagerie

There are a few ways of doing things in Kivy, so before we get into the widgets themselves, let’s start with a quick overview; here is a super simple app that has a GridLayout and a Button Widget :

import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
class oneWidgetApp(App):
def build(self):
layout = GridLayout(cols=2)
layout.add_widget(Button(text='Widget 1'))
return layout
if __name__ == '__main__':
oneWidgetApp().run()

And the resulting App:

Adding more widgets at first seems trivial, for instance here we have 4 widgets inside the same GridLayout:

import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.switch import Switch
from kivy.uix.button import Button
from kivy.uix.slider import Slider
class manyWidgetsApp(App):
def build(self):
layout = GridLayout(cols=2)
layout.add_widget(Button(text='Widget 1'))
layout.add_widget(Switch())
layout.add_widget(Slider())
layout.add_widget(Button(text='Widget 4'))
return layout
if __name__ == '__main__':
manyWidgetsApp().run()

The Kivy way ?

Issues start appearing when you realize that some widgets have a simple API, so for instance adding a label to the switch is not an argument, but rather needs to be added at the container level, in order to deal with this and other issues, Kivy comes with it’s own language, let’s redo the previous example:

#OneWidgetV2.py...import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
class oneWidgetV2(App):
def build(self):
return GridLayout()
if __name__ == '__main__':
oneWidgetV2().run()

And you’d also need a .kv file to go along (OneWidgetV2.kv), UI composition now happens here:

<GridLayout>:
cols: 2
Button:
text: 'Widget 1'
background_color : [1,0,0,1]
❗️ Note that you don't have to import the Button module, also we added and extra argument ( background_color ), a list of widget arguments can be found in the API reference: https://kivy.org/doc/stable/api-kivy.uix.button.html#kivy.uix.button.Button

An alternative way if you prefer using a single python file ( this also allows you to load and unload widgets via the builder) :

#OneWidgetV2b.py...import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout
Builder.load_string('''
<GridLayout>:
cols: 2
Button:
text: 'Widget 1'
background_color : [0,1,0,1]
''')
class oneWidgetV2b(App):
def build(self):
return GridLayout()
if __name__ == '__main__':
oneWidgetV2b().run()

These 2 alternative ways of building your GUI at first seem a bit clunky, but become second nature after a little practice, if you are coming from the web, think about it in terms of HTML/JS and CSS/SASS/LESS..


Bindings

Onwards then, the next thing we need to briefly discuss is bindings,chances are you are also coding the backend or logic of your app, so we need to hand user input in Kivy to python, let’s start with a simple click counter:

#buttonBind.py...import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
class buttonBindApp(App):clickcounter = 0def build(self):
layout = GridLayout(cols=2)
layout.add_widget(
Button(
text='I\'ve been clicked ' +
str(self.clickcounter) + ' times',
on_press=self.update))

return layout
def update(self, obj):
self.clickcounter += 1
obj.text = 'I\'ve been clicked ' + str(self.clickcounter) + ' times'
if __name__ == '__main__':
buttonBindApp().run()

Once more there are a few ways to do the same thing, we could for instance rephrase the Button widget in a more explicit way:

#buttonBindV2.py...import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
class buttonBindV2App(App):clickcounter = 0def build(self):
layout = GridLayout(cols=2)
button = Button(
text='I\'ve been clicked ' +
str(self.clickcounter) + ' times')
layout.add_widget(button)
button.bind(on_press=self.update)
return layout
def update(self, obj):
self.clickcounter += 1
obj.text = 'I\'ve been clicked ' + str(self.clickcounter) + ' times'
if __name__ == '__main__':
buttonBindV2App().run()

Note the use of bind after the widget has been added,in general any event (see also custom and self updating ones) can be bound to a callback function.

Binding the Kivy Way:

The other thing you need to know is how to bind a python function via the Kivy language, the previous example for instance can once more be rewritten as follows:

#buttonBindV3.py...import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.properties import NumericProperty
class buttonBindV3App(App):clickCounterProperty = NumericProperty(0)def build(self):
return GridLayout()
def update(self):
self.clickCounterProperty += 1
if __name__ == '__main__':
buttonBindV3App().run()

And the .kv file:

# buttonBindV3.kv<GridLayout>:
cols: 2
Button:
text : str(app.clickCounterProperty)
background_color : [1,0,0,1]
on_press: app.update()

Note that we are now using kivy properties, which are observables, so no need to bind them explicitly, you add them at the kivy language level and they self update which is very cool ( complex types might need to be precomposed though and observables have other qualities, check the docs).


WIDGETS

This was by no means a complete overview, Kivy also comes with timing, storage, network and graphic utilities amongst others, check the API for more, for now let’s overview a couple of the more popular widgets and finally I’ll tell you how to sample the rest…

Slider ⬅️ check additional options in the API reference

#slider.py... Just a shell for the root layout...import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
class sliderApp(App):
def build(self):
return GridLayout()
if __name__ == '__main__':
sliderApp().run()

And the slider in Kivy language…

# slider.kv...<GridLayout>:
cols: 2
Slider:
id: s1
Label:
text: '{}'.format(s1.value)
❗️ A new thing; here we are using an id to reference the widget and get the text for the Label next to it, this is part of the Kivy language and makes referencing widgets a breeze, check out more here:https://kivy.org/doc/stable/guide/lang.html#referencing-widgets

Text Input ⬅️ check additional options in the API reference

#textInput.py... same shell different animal: )import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
class textInputApp(App):
def build(self):
return GridLayout()
if __name__ == '__main__':
textInputApp().run()

And the textInput widget in Kivy language…

# textInput.kv<GridLayout>:
cols: 2
TextInput:
id: t1

Label:
text: t1.text

It seems trivial to add a text input box, the only thing that really changed is the label binding (.text instead of .value) but chances are you might need something different, check the API reference for a ton of extra features revolving text; out of the box though you get a ton of functionality like copy/paste/select etc,etc.


Action Bar ⬅️ check additional options in the API reference

Let’s now make a slightly more complex widget in the form of an action bar which is pretty common in desktop applications..

#actionBar.py... NOTE we are using the Action Bar as the root widget hereimport kivy
from kivy.app import App
from kivy.uix.actionbar import ActionBar
class actionBarApp(App):
def build(self):
return ActionBar()
if __name__ == '__main__':
actionBarApp().run()

And the Action Bar in Kivy…

# actionBar.kv<ActionBar>:
pos_hint: {'top':1}
ActionView:
use_separator: True
ActionPrevious:
app_icon: ''
title: 'Such Action'
with_previous: False
ActionOverflow:
ActionButton:
text: 'Btn2'
ActionButton:
text: 'Btn3'
ActionGroup:
text: 'Group1'
ActionButton:
text: 'Btn5'
ActionButton:
text: 'Btn6'

It is a bit more complex in that there is some extra nesting and specific arguments that only apply to an action bar, ( you know the drill, consult the API ) but in essence has the same widget architecture which is the focus here.


The Rest:

At this point, rather than keep on listing all the widgets as I had Initially planned, I’d rather not repeat what is already available, hear me out…

Kivy comes with a ton of examples of the individual widgets and a showcase demo which is particularly helpful since it allows you to both preview the widget and how it is written in Kivy language, so as you are building your GUI you can get ideas and troubleshoot as needed for your specific requirements…

../examples/demo/showcase/main.py...
⁉️ Where to get the examples ?The main example directory can be found at Kivy's Repo :https://github.com/kivy/kivyYou can also get a frozen copy from this posts repo:https://github.com/KenoLeon/KivyMenagerie

What Next ? A good place to go next is to explore the individual widgets as needed ../examples/widgets/ there are also quite a few applications in the examples folder that can help you when you are ready to implement an application.

Happy Trails !

About the Author :

Born Eugenio Noyola Leon (Keno) I am a Designer,Web Developer/programmer, Artist and Inventor, currently living in Mexico City, you can find me at www.k3no.com

Keno Leon

Written by

Keno Leon

AI, Software Developer, Designer : www.k3no.com

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade