Skip to content

Debugging Kivy Widgets and Python UI programming

The side project and my attempts to avoid Javascript

I’m running a side project currently which involves building a user interface in Python. Why Python? Well, essentially, for me, I am plagued with existential terror when I contemplate (even for a moment) learning React or building anything using a JavaScript web framework from the ground up. My client app will have to be responsive to touch events and communicate to an external API upon certain events, and the idea of having to dive again into AJAX with JavaScript gives me the heebie-jeebies. There are just too many ways to do one simple thing, and it causes me endless frustration. Python, on the other hand, has certain idiomatic ways to approach certain problems and this jives better with me.

enter tkinter

I must say however, that with this specific project, both languages have the same issue. For Python, there are more than a handful of UI modules available – the built-in Tkinter and several external modules, such as wxPython or Kivy. My initial idea for my client application was to lean on Tkinter because it comes pre-bundled with the Python programming language and might therefore be easier to ship and distribute to other potential users. What I learned was that Tkinter has a long history of use and due to this long history, there is a lot of old documentation and guides. This caused me problems when looking for solutions for simple issues, such as which Geometry manager to use. Recent documentation suggests that the Grid Geometry manager is the way to go – but every single community post with tutorials around Tkinter uses the Pack Geometry manager. Essentially then you have a situation where the module’s creators urge the development community to use on type of Geometry manager but the overwhelming majority of users and developers using another older and more complex Geometry manager, for whatever reason.. I actually, as an aside, believe that this is because the Pack Geometry manager was supported before Grid (which was provided with a later release) but the end result, for me, is the same. Difficulty in learning simple things and confusion about the basics is not a great way to start!

kivy to the rescue

kivy project image

So after flailing around with Tkinter for a few hours and deciding (correctly) to swap to another UI Framework, I jumped on Kivy. Kivy promises to support all major platforms with the same Python code and brings native support for touch enabled devices. My project isn’t necessarily intended to support touchscreen, but hey, I’m not gonna complain. Kivy also approaches app design with a slightly new paradigm (at least from Python’s perspective) – creating a new markup language, similar in many ways to YAML, the .kv language. This language takes care of the visual layout and many of the UI behaviours, leaving the Python programming file to deal with application logic and integration with external APIs etc. My first foray involved a simple pre-baked setup :

The corresponding .kv file I was working with :

So in essence, as you can probably tell in the .kv markup above, the ‘MyFirstAppFlow’ entry is the ‘root’ widget, or the top of the hierarchical tree. Under this we have a ‘BoxLayout’ which apportions screen real-estate equally among the child widgets. Critically, it (for example) would divvy up 50% of screen space between two child widgets, but if you have the desired size of one of these widgets set to 50%, it’s only going to get 50% of the 50% it was apportioned by the parent BoxLayout (ouch). So here we have our ‘BoxLayout’ set to take up all of the available size given by the root widget, with a ‘vertical’ orientation. There are two children here, a ‘GridLayout’ and another ‘BoxLayout’. Under the ‘BoxLayout’ there is further a ‘Label’ and ‘TextInput’, under the ‘GridLayout’ there are several ‘Button’ widgets. You can probably see how multiple widgets can get pretty complicated pretty quickly, right? Here’s a snapshot of how that looks when launched :

Resulting Kivy app from markup above

…I mean, it doesn’t look *terrible* – but it’s really hard to see where the overlap is and where each widget is being apportioned screen real-estate.

Fortunately, we have a neat debugging solution – the Kivy module ‘inspector’. You simply invoke your python file containing the program logic and call the module on the cli thusly:

This will launch your app, and it probably won’t be immediately noticeable what the change is. Simply press ctrl+e to bring up the ‘inspector’ interface and click anywhere on the screen to see which widget is owning a specific part of the UI

As you can see here, clicking the ‘Label Text here…’ section indicates this is the ‘Label’ under the vertically aligned ‘BoxLayout’ (which is a subdivision under another BoxLayout). It also visually indicates the widget size and location in red. Neat huh? You can also click on the ‘Label object’ on the panel to expand the details of the object and can on the left side of the section once expanded totally walk the UI tree from child to parent layout or widget! This is a fantastic visual aid to debug why a UI element is being sized and/or placed in a specific place within your app and it’s usefulness can’t be overstated! And for my next trick, I will figure out how to give the buttons and GridLayout ownership of the leftmost column, reducing the overall size of the TextInput and Label widgets. Stay tuned for the next post with the results!

Leave a Reply

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