Posts tagged ‘kivy’

Creating Apps In Kivy: The Book

I apologize for my near-silence over the past few months. I’ve packed house and moved twice in that time, started a new job, and, relevant to this post, written a book.

My Creating an application in Kivy blog series has been by far the most popular set of posts on this blog. It garners about 200 views per day, and has been doing so for nearly a year. This taught me a very important lesson: posts with controversial titles, (notably this one, but basically anything that has hit hacker news) are much less valuable than posts with meaningful long-term content. Getting a few thousand hits in one day is pretty satisfying, but when most of your “readers” simply comment on the post without having read the article, that hit-count becomes meaningless.

“Creating an application in Kivy”, on the other hand, has had sixteen thousand visits to part 1, and nearly three thousand of those have made their way all the way to part 9. I could definitely achieve more hits per day by writing a new minimum-content controversial article every day, but these visitors keep coming with no effort on my part. This is lucky, as the focus on writing solid content for my book has taken time away from writing solid content for this blog.

And with that, I’d like to announce that Creating Apps In Kivy is now available. This project started when the aforementioned tutorial caught the eye of an O’Reilly editor. They helped me put together a great book that I am proud of and confident you will enjoy.

Creating Apps in Kivy covers many of the topics discussed in my tutorial, but in more depth and with much more polish. Like the tutorial, it takes you from “new to Kivy” to creating and deploying a complete application to your Android or iOS device. It’s a fun, short read and I’m proud to present it to you today. If you liked the tutorial, buying my book would be a great way to support my work!

Creating an Application in Kivy: Part 9

Welcome to the final part of this series on creating a working Jabber client in Kivy. While there are numerous things we could do with our code to take it to Orkiv version 2, I think it’s currently in a lovely state that we can call “finished” for 1.0.

In this article, we’re going to talk about releasing and distributing Kivy to an Android mobile device. We’ll use a tool called buildozer that the Kivy developers have written. These commands will, in the future, extend to other operating systems.

We aren’t going to be writing a lot of code in this part (some adaptation to make it run on android is expected). If you’re more interested in deploying than coding, you can check out my state of the orkiv repository as follows:

git clone https://github.com/buchuki/orkiv.git
git checkout end_part_eight

Remember to create and activate a virtualenv populated with the appropriate dependencies, as discussed in part 1.

Table Of Contents

Here are links to all the articles in this tutorial series:

  1. Part 1: Introduction to Kivy
  2. Part 2: A basic KV Language interface
  3. Part 3: Handling events
  4. Part 4: Code and interface improvements
  5. Part 5: Rendering a buddy list
  6. Part 6: ListView Interaction
  7. Part 7: Receiving messages and interface fixes
  8. Part 8: Different views for different screens
  9. Part 9: Deploying your kivy application

Restructuring the directory

Back in Part 1, we chose to put all our code in __main__.py so that we could run it from a zip file or directly from the directory. In some ways, this is pretty awesome for making a package that can easily be distributed to other systems (assuming those systems have the dependencies installed). However, Kivy’s build systems presume that the file is called main.py.

I’m not overly happy about this. Kivy sometimes neglects Python best practices and reinvents tools that are widely used by the Python community. That said, it is possible for us to have the best of both worlds. We can move our code into orkiv/main.py and still have a __main__.py that imports it.

First, move the entire __main__.py file into main.py, using git:

    git mv orkiv/__main__.py orkiv/main.py

Next, edit the new main.py so that it can be imported from other modules without automatically running the app. There is a standard idiomatic way to do this in python. Replace the code that calls Orkiv().run() with the following:

(commit)

    def main():
        Orkiv().run()

    if __name__ == "__main__":
        main()

There are two things going on here. First, we moved the code that instantiates the application and starts it running in a function called main(). There is nothing exciting about this function. It does the same thing that used to happen as soon as the module was imported. However, nothing will happen now unless that function is called.

One way to regain the previous functionality of immediately running the app when we type python main.py would be to just call main() at the bottom of the module. However, that is not what we want. Instead, our goal is to make the application automatically run if the user runs python orkiv/main.py, but if they run import main from a different module or the interpreter, nothing is explicitly run.

That’s what the if __name__ conditional does. Every module that is ever imported has a magic __name__ attribute. This is almost always the name of the module file without the .py extension (eg: main.py has a __name__ of main). However, if the module is not an imported module, but is the script that was run from the command line, that __name__ attribute is set to __main__ instead of the name of the module. Thus, we can easily tell if we are an invoked script or an imported script by testing if __name__ is __main__. Indeed, we are taking advantage of the same type of magic when we name a module __main__.py. When we run python zipfile_or_directory it tries to load the __main__ module in that directory.

However, we do not currently have a __main__ module, since we just moved it. Let’s rectify that:

    from main import main
    main()

Save this as a new orkiv/__main__.py and test that running python orkiv from the parent directory still works.

You’ll find that the window runs, however, if you try to connect to a jabber server, you get an exception when it tries to display the buddy list. This is because our orkiv.kv file was explicitly importing from __main__. Fix the import at the top of the file so that it imports from main instead:

#:import la kivy.adapters.listadapter
#:import ok main

OrkivRoot:

While we’re editing code files, let’s also add a __version__ string to the top of our main.py that the Kivy build tools can introspect:

(commit)

    __version__ = 1.0

Deploying to Android with buildozer

Deploying to Android used to be a fairly painful process. Back in December, 2012, I described how to do it using a bulky Ubuntu virtual machine the Kivy devs had put together. Since then, they’ve designed a tool called buildozer that is supposed to do all the heavy lifting. Once again, I have some issues with this plan; it would be much better if Kivy integrated properly with setuptools, the de facto standard python packaging system than to design their own build system. However, buildozer is available and it works, so we’ll use it. The tool is still in alpha, so your mileage may vary. However, I’ve discovered that Kivy products in alpha format are a lot better than final releases from a lot of other projects, so you should be ok.

Let’s take it out for a spin. First activate your virtualenv and install the buildozer app into it:

    . venv/bin/activate
    pip install buildozer

Also make sure you have a java compiler, apache ant, and the android platform tools installed. This is OS specific; these are the commands I used in Arch Linux:

    sudo pacman -S jdk7-openjdk
    sudo pacman -S apache-ant
    yaourt android-sdk-platform-tools

Then run the init command to create a boilerplate buildozer.spec:

    buildozer init

Now edit the buildozer.spec to suit your needs. Most of the configuration is either straightforward (such as changing the application name to Orkiv) or you can keep the default values. One you might overlook is that source.dir should be set to orkiv the directory that contains main.py.

The requirements should include not only kivy and sleekxmpp but also dnspython, a library that sleekxmpp depends on. You can use the pip freeze command to get a list of packages currently installed in your virtualenv. Then make a conscious decision as to whether you need to include each one, remembering that many of those (cython, buildozer, etc) are required for development, but not Android deployment.

For testing, I didn’t feel like creating images for presplash and the application icon, so I just pointed those at icons/available.png. It’s probably prettier than anything I could devise myself, anyway!

If you want to see exactly what changes I made, have a look at the diff.

The next step is to actually build and deploy the app. This takes a while, as buildozer automatically downloads and installs a wide variety of tools on your behalf. I don’t recommend doing it over 3G!

First, Enable USB debugging on the phone and plug it into your development machine with a USB cable. Then tell buildozer to do all the things it needs to do to run a debug build on the phone:

buildozer android debug deploy run

I had a couple false starts before this worked. Mostly I got pertinent error messages that instructed me to install the dependencies I mentioned earlier. Then, to my surprise, the phone showed a Kivy “loading…” screen. Woohoo! It worked!

And then the app promptly crashed without any obvious error messages or debugging information.

Luckily, such information does exist. With the phone plugged into usb, run adb logcat from your development machine. Review the Python tracebacks and you’ll discover that it is having trouble finding the sound file in.wav:

I/python  (25368):    File "/home/dusty/code/orkiv/.buildozer/android/platform/python-for-android/build/python-install/lib/python2.7/site-packages/kivy/core/audio/__init__.py", line 135, in on_source
I/python  (25368):    File "/home/dusty/code/orkiv/.buildozer/android/platform/python-for-android/build/python-install/lib/python2.7/site-packages/kivy/core/audio/audio_pygame.py", line 84, in load
I/python  (25368):    File "/home/dusty/code/orkiv/.buildozer/android/platform/python-for-android/build/python-install/lib/python2.7/site-packages/android/mixer.py", line 202, in __init__
I/python  (25368):  IOError: [Errno 2] No such file or directory: '/data/data/ca.archlinux.orkiv/files/orkiv/sounds/in.wav'
I/python  (25368): Python for android ended.

The problem here is that the code specifies a relative path to the sound file as orkiv/sounds/in.wav. This worked when we were running python orkiv/ from the parent directory, but python for android is running the code as if it was inside the orkiv directory. We can reconcile this later, but for now, let’s focus on getting android working and just hard code the file location:

(commit)

    self.in_sound = SoundLoader.load("sounds/in.wav")

While we’re at it, we probably also need to remove “orkiv” from the location of the icon files in orkiv.kv:

    source: "icons/" + root.online_status + ".png"

Finally, running buildozer and adb logcat again indicates the error message hasn’t changed. This is because we aren’t explicitly including the .wav file with our distribution. Edit buildozer.spec to change that:

    # (list) Source files to include (let empty to include all the files)
    source.include_exts = py,png,jpg,kv,atlas,wav

Run the buildozer command once again and the app fire up and start running! Seeing your Python app running on an Android phone is a bit of a rush, isn’t it? I was able to log into a jabber account, but selecting a chat window goes into “narrow” mode because the phone’s screen has a much higher pixel density than my laptop. We’ll have to convert our size handler to display pixels somehow.

I was able to send a chat message, which was exciting, but when the phone received a response, it crashed. Hard. adb logcat showed a segmentation fault or something equally horrifying. I initially guessed that some concurrency issue was happening in sleekxmpp, but it turned out that the problem was in Kivy. I debugged this by putting print statements between each line in the handle_xmpp_message method and seeing which ones executed before it crashed. It turned out that Kivy is crashing in its attempt to play the .wav file on an incoming message. Maybe it can’t handle the file format of that particular audio file or maybe there’s something wrong with the media service. Hopefully the media service will be improved in future versions of Kivy. For now, let’s use the most tried and true method of bugfixing: pretend we never needed that feature! Comment out the line:

(commit)

    #self.in_sound.play()

and rerun buildozer android debug deploy run.

Now the chat application interacts more or less as expected, though there are definitely some Android related quirks. Let’s fix the display pixel issue in orkiv.kv:

(commit)

    <OrkivRoot>:
        mode: "narrow" if self.width < dp(600) else "wide"
        AccountDetailsForm:

All I did was wrap the 600 in a call to dp, which converts the 600 display pixels into real pixels so the comparison is accurate. Now when we run the app, it goes into “narrow” mode because the screen is correctly reporting as “not wide enough for wide mode”. However, if you start the app in landscape mode, it does allow side-by-side display. Perfect!

And that’s the app running on Android. Unfortunately, in all honesty, it’s essentially useless. As soon as the phone display goes to sleep, the jabber app closes which means the user is logged out. It might be possible to partially fix this using judicious use of Pause mode. However, since the phone has to shut down internet connectivity to preserve any kind of battery life, there’s probably a lot more involved than that.

On my phone, there also seems to be a weird interaction that the BuddyList buttons all show up in a green color instead of the colors specified in the Kivy language file and the args_converter.

Third, the app crashes whenever we switch orientations. This is probably a bug fixable in our code rather than in Kivy itself, but I don’t know what it is.

Also, touch events are erratic on the phone. Sometimes the scroll view won’t allow me to scroll when I first touch it, but immediately interprets a touch event on the ListItem. Sometimes touch events appear to be forgotten or ignored and I have to tap several times for a button to work. Sometimes trying to select a text box utterly fails. I think there must be some kind of interaction between Kivy’s machinery and my hardware here, but I’m not certain how to fix it.

Occasionally, when I first log in, the BuddyList refuses to act like a ScrollView and the first touch event is interpreted as opening a chat instead of scrolling the window. This is not a problem for subsequent touch events on the buddy list.

Finally, there are some issues with the onscreen keyboard. When I touch a text area, my keyboard (I’m using SwiftKey) pops up, and it works well enough. However, the swipe to delete behavior, which deletes an entire word in standard android apps, only deletes one letter here. More alarmingly, when I type into the password field, while the characters I typed are astrisk’d out in the field, they are still showing up in the SwiftKey autocomplete area. There seems to be some missing hinting between the OS and the app for password fields.

Before closing, I’d like to fix the problem where the app is no longer displaying icons on the laptop when I run python orkiv/. My solution for this is not neat, but it’s simple and it works. However, it doesn’t solve the problem if we put the files in a .zip. I’m not going to worry about this too much, since buildozer is expected, in the future, to be able to make packages for desktop operating systems. It’s probably better to stick with Kivy’s tool. So in the end, this __main__.py feature is probably not very useful and could be removed. (Removing features and useless code is one of the most important parts of programming.) However, for the sake of learning, let’s make it work for now! First we need to add a root_dir field to the Orkiv app. This variable can be accessed as app.root_dir in kv files and as Orkiv.get_running_app().root_dir in python files.

(commit)

    class Orkiv(App):
        def __init__(self, root_dir):
            super(Orkiv, self).__init__()
            self.root_dir = root_dir
            self.xmpp = None

Of course, we also have to change the main() function that invokes the app to pass a value in. However, we can have it default to the current behavior by making the root_dira keyword argument with a default value:

    def main(root_dir=""):
        Orkiv(root_dir).run()

Next, we can change the __main__.py to set this root_dir variable to orkiv/:

    from main import main
    main("orkiv/")

The idea is that whenever a file is accessed, it will be specified relative to Orkiv.root_dir. So if we ran python main.py from inside the orkiv/ directory (this is essentially what happens on android), the root_dir is empty, so the relative path is relative to the directory holding main.py. But when we run python orkiv/ from the parent directory, the root_dir is set to orkiv, so the icon files are now relative to the directory holding orkiv/.

Finally, we have to change the icons line in the kivy file to reference app.root_dir instead of hardcoding the path (a similar fix would be required for the sound file if we hadn’t commented it out):

    Image:
        source: app.root_dir + "icons/" + root.online_status + ".png"

And now, the app works if we run python orkiv/ or python main.py and also works correctly on Android.

There are a million things that could be done with this Jabber client, from persistent logs to managed credentials to IOS deployment. I encourage you to explore all these options and more. However, this is as far as I can guide you on this journey. Thus part 9 is the last part of this tutorial. I hope you’ve enjoyed the ride and have learned much along the way. Most importantly, I hope you’ve been inspired to start developing your own applications and user interfaces using Kivy.

Financial Feedback

Writing this tutorial has required more effort and consumed more time than I expected. I’ve put on average five hours per tutorial (with an intended timeline of one tutorial per week) into this work, for a total of around 50 hours for the whole project.

The writing itself and reader feedback has certainly been compensation enough. However, I’m a bit used up after this marathon series and I’m planning to take a couple months off before writing anything like this tutorial again in my free time.

That said, I have a couple of ideas for further tutorials in Kivy that would build on this one. I may even consider collecting them into a book. It would be ideal to see this funded on gittip, but I’d want to be making $20 / hour (far less than half my normal wage, so I’d still be “donating” much of my time) for four hours per week before I could take half a day off from my day job to work on such pursuits — without using up my free time.

A recent tweet by Gittip founder Chad Whitacre suggests that people hoping to be funded on gittip need to market themselves. I don’t want to do that. I worked as a freelancer for several years, and I have no interest in returning to that paradigm. If I have to spend time “selling” myself, it is time I’m not spending doing what I love. In my mind, if I have to advertise myself, then my work is not exceptional enough to market itself. So I leave it up to the community to choose whether to market my work. If it is, someone will start marketing me and I’ll see $80/week in my gittip account. Then I’ll give those 4 hours per week to tutorials like this or other open source contributions. If it’s not, then I’ll feel more freedom to spend my free time however I like. Either way, I’ll be doing something that I have a lot of motivation to do.

Regardless of any financial value, I really hope this tutorial has been worth the time you spent reading it and implementing the examples! Thank you for being an attentive audience, and I hope to see you back here next time, whenever that is!

Creating Apps In Kivy: The Book

My request for crowd funding above didn’t take off. I’m making just under $12 per week on Gittip, all of which I’m currently regifting. Instead of my open contribution dream being fulfilled, I opted to follow the traditional publishing paradigm and wrote a book Creating Apps In Kivy, which was published with O’Reilly. I’m really excited about this book; I think it’s the highest quality piece of work I have done. If you enjoyed this tutorial, I encourage you to purchase the book, both to support me and because I think you’ll love it!

Creating an Application in Kivy: Part 8

Sorry for the delay in posting this, folks. I’ve been away on vacation and then at Pycon Canada, which was amazing. And another apology, in advance, that this article is going to be bloody short compared to parts 1 through 7. That’s not only because I’m short on time; it also turned out that what I wanted to do was easier than I expected!

Anyway, time for content! Now that we have a working jabber client, is our job done? The client is certainly functional, but I’d still like to experiment with displaying a different representation depending on the size of the window. Specifically, if it is wider than a certain number of pixels, let’s show the buddy list beside the chat window; otherwise, let’s stick with the switching back and forth that we currently have.

If you haven’t been following along or want to start this example at the same point at which I’m starting, you can clone the github repository with my examples:

git clone https://github.com/buchuki/orkiv.git
git checkout end_part_seven

Remember to create and activate a virtualenv populated with the appropriate dependencies, as discussed in part 1.

Table Of Contents

Here are links to all the articles in this tutorial series:

  1. Part 1: Introduction to Kivy
  2. Part 2: A basic KV Language interface
  3. Part 3: Handling events
  4. Part 4: Code and interface improvements
  5. Part 5: Rendering a buddy list
  6. Part 6: ListView Interaction
  7. Part 7: Receiving messages and interface fixes
  8. Part 8: Width based layout
  9. Part 9: Deploying your Kivy application

Thinking through design

Since I’m not entirely certain how I want this code (or interface) to look, let’s spend a few paragraphs describing it so we all know we’re developing the same thing. It’s simple to say “we want chat windows to display beside the buddy list when the screen is big enough”, but what does that mean exactly? At what points in the code do we have to handle it? I’m actually “thinking out loud” here so you can see the various paths a brain can follow when programming.

Let’s follow the process from program startup. When the account credentials are displayed, we may as well just show the form no matter how big the screen is. When the Buddy List is first displayed after login, it can take up the whole screen as well. It’s not until we open our first chat that we have to decide if we are going to add the new chat beside the buddy list or to replace it. Of course, it’s not just a matter of adding the chat window, we also have to remove any existing chat windows, since we don’t just want to keep adding windows every time they click a new buddy. One way we could do this is add a ChatWindowContainer and ensure that widget only contains one chat window. Another is to keep track of which widows are loaded and unload them as needed. A third option is to clear all widgets and add both the Buddy List and Chat Window to a clean slate.

Regardless of the width of the screen, when the user clicks the “Buddy List” button in the chat window, it should do the same thing: close all chat windows and show only the buddy list, full width. One option worth exploring is to hide that button when we are in wide screen view. Or perhaps the button should be removed altogether; a gesture might be a better interface. While gestures are all the rage in mobile devices right now, I’m not a fan of them from an affordance perspective. It’s never clear to the end user when or where a gesture is appropriate. While I use them extensively in my highly customized AOKP installation, I wouldn’t want to explain a gesture based interface to my parents.

In addition to deciding what to render when chat windows are added or removed, we need to do something when the window changes size. If it is in wide screen mode while a chat window is displayed, and then gets smaller, we have to remove the buddy list to switch to the original behavior. If it is in narrow mode while a chat window is displayed and it gets wider, we have to add the buddy list back.

I feel like it would be wise to have a “mode” property bound to the window size, so that we always know whether we are currently supposed to be in wide or narrow mode. However binding that property to size means that the mode will change without telling us what the “old” mode was. Thus, we have no way to know whether the mode we are supposed to be in is the one we are currently in. On the other hand, such information can be inferred from the size or contents of the child list on the OrkivRoot object.

Finally, it seems most of our calculations can be simplified by noticing that we only have to do things different if a chat window is currently displayed or about to be displayed.

Now I think I have a plan in my head. You may or may not have come to the same conclusions while reading the above, and it’s possible you’ve had some better ideas. That said, this is how I intend to implement this. It looks like it’s going to be simpler than I originally expected. Hooray for thinking things through in advance!

1. Add a mode property to OrkivRoot that is automatically set from the size of the window
2. Add chat_visible and budddy_list_visible python properties (not kivy properties) that tells us if there are buddy list or chat windows visible.
3. Check the mode when adding a chat window and decide whether to replace the buddy list or not
4. On a size event, if a chat window is currently visible, determine whether the buddy list needs to be added or removed.

Properties

We’ve looked at Kivy properties in past parts of this tutorial, and you may already be familiar with Python properties. It’s somewhat unfortunate that the same word is being used to explain two different programmatic concepts. However, there are only so many words to describe the idea of a “characteristic”, and this idea is extremely common in many different programming libraries. So some overloading of terminology is inevitable. I tend to use the phrase “Kivy property” to refer to the kinds of properties that Kivy supplies. Kivy properties are pretty cool because they can automatically update themselves when other properties change and events can be bound to them so that those other properties also update themselves. In other words, Kivy properties are smart.

Python properties are not stupid, mind you. People sometimes have trouble wrapping their mind around Python properties, but they’re actually pretty simple. It might be convenient to think of python properties as just a way to make a method look like an attribute. Thus, you can access something like node.color and underneath the hood, it’s actually behaving as though node.color() was called. However, they’re even more interesting than that, because you can actually call a completely different method when you set the value of the property. Thus node.color = "red" can do about the same thing as node.color("red").

The confusing thing about python properties is not so much “how do I do this?” as “why would I do this”? There are many problem-specific answers, but two general ones come to mind. The first is the Python idiom that readability counts. In general, when you access a property on an object, you are doing something with an adjective on a noun. In contrast, when you call a method on an object, you are doing something (a verb) to a noun. However, sometimes when you are manipulating an adjective, you need to do a little extra calculation or manipulation when the value is set or accessed. Using properties, it’s possible for the code accessing the property to read “naturally”, as though you were doing something with an adjective on a noun, even though there is actually a little “doing to” going on as well.

The second reason is actually an evolution of the first. Often, in the first version of an API, we just add an attribute to an object and allow client code to manipulate it. Then, in a later iteration of the code, we want to do some kind of calculation, caching, or validation on these attributes. However, we can’t suddenly change the attribute into a method or the old client code will break. However, we can use properties to add these new manipulations and keep the original API, which is probably more readable from the calling code’s perspective, anyway.

At any rate, our OrkivRoot class needs to have one Kivy property and two Python properties in order to perform the calculations for treating the screen differently depending on its size:

(commit)

    class OrkivRoot(BoxLayout):
        mode = StringProperty("narrow")

        @property
        def chat_visible(self):
            return ChatWindow in {c.__class__ for c in self.children}

        @property
        def buddy_list_visible(self):
            return self.buddy_list in self.children

So we have a simple mode property that is exactly the same as any other Kivy property. We also have two read only python properties named buddy_list_visible and chat_visible. The former just checks if the buddy_list object is one of the children. The latter loops through the children of OrkivRoot and checks if any of them are instances of the ChatWindow class. Any time you access orkivroot.chat_visible, this method is executed.

The odd notation in the chat_visible property may need some explanation. (Note: If you’re running python 2.6 or older, it won’t even run) Python has a variety of comprehension syntaxes that allow us to create new iterator objects such as lists, generators, dictionaries, and sets based on existing iterators. This syntax is optimized for efficiency as compared to looping over one iterator and manually adding it to another. It’s also more readable if you know the syntax.

The braces, which you are probably used to denoting a dictionary, in this case actually generate a set, based on the contents of another iterator: self.children. For each element in self.children it adds the class of that element to the new set. Then the in operator is used to determine if a ChatWindow class is in that set.

In theory, we use a set instead of a list for efficiency. However, in this case, I’m actually only using it for pedagogy. The in keyword supports much faster lookups in a large set than it does in a large list. However, in this case, the number of children of a OrkivRoot will never be large. I’m just trying to drive home the point that different data structures have different strengths and weaknesses, and you need to choose them wisely. For example, a few months ago, one of my colleagues shaved nearly an hour off our loading process by converting a list to a set in this very fashion.

I hope you find my digressions educational! As I’ve said before, my goal is to not just explain how to build a Jabber application in Kivy, but to demonstrate the various thought processes behind designing your own application in whatever programming language or library you might choose.

Let’s ignore those python properties for a bit and look back at that Kivy property. While the mode StringProperty has been defined, it’s not yet being set to anything. Let’s fix that in the Kivy language file:

(commit)

    <OrkivRoot>
        mode: "narrow" if self.width < 600 else "wide"
        AccountDetailsForm:

That one new line of code is all that is needed to have a dynamically updating mode attribute. Any time the window size changes, the mode will automatically (it’s almost automagic, in fact) be set to either “narrow” or “wide” depending on what the width is. Kivy properties are very powerful. The width property of widget is automatically updated whenever the window gets resized. Then the Kivy language does a wonderful job of hooking up the event bindings such that any time that width changes, a callback that executes the line of code above is invoked.

For the record, I tested these properties by adding a couple print() statements when the show_buddy_chat method is invoked to render the current mode.

Make it work

Now we need to rework the show_buddy_chat method just a little:

(commit)

    def show_buddy_chat(self, jabber_id):
        self.clear_widgets()
        if self.mode == "wide":
            self.add_widget(self.buddy_list)
        self.add_widget(self.get_chat_window(jabber_id))
        self.buddy_list.new_messages.discard(jabber_id)
        self.buddy_list.force_list_view_update()

Instead of explicitly removing the buddy_list, we now start with a clean slate by calling clear_widgets. Then we check if the mode is “wide” and add the buddy_list if it is. Then the chat window is added just like before, but now if the view is wide, it will peacefully slide in beside the buddy_list instead of replacing it.

The code for changing the window contents when the mode changes is a bit longer. The logic is simple, it’s just verbose. We need to add an on_mode method to the OrkivRoot. This method will only be fired when the mode changes thanks, once again, to the magic of Kivy properties.

(commit)

def on_mode(self, widget, mode):
    if mode == "narrow":
        if self.chat_visible and self.buddy_list_visible:
            self.remove_widget(self.buddy_list)
    else:
        if self.chat_visible and not self.buddy_list_visible:
            self.add_widget(self.buddy_list, index=1)

When I first tested this method, it failed because I didn’t accept any arguments on the event. So I had to figure out what the expected arguments were. I did this by making the method accept *args, which says “put all the non-keyword arguments in a list named args”. Then I printed that list to see what they were. So I knew that the arguments passed were a widget object and the current value of mode. Introspection in Python is so easy!

If the mode is narrow, it checks if both widgets are currently visible and removes the buddy_list if this is the case. The only way both widgets could be visible on an on_mode event is if the mode just switched from wide to narrow.

If the mode is wide, it checks if a chat window is visible and the buddy list is not. My first attempt only checked if the buddy_list was not visible and added it arbitrarily. This failed on startup, since OrkivRoot has a size, and therefore a mode, right from startup, even when the login form is being displayed. Thus, we only do the widget juggling if a chat_window is currently visible.

The index=1 argument to add_widget tells it to insert the buddy_list before the already visible chat_window rather than after.

And that’s it! Test that, try switching back and forth between the buddy list and the chat window, try resizing the window, try switching chats while the buddy list is visible. I’m a little dubious that it’s perfect, but I can’t find a situation where these few lines of code aren’t enough to do what I want. That’s rather unfortunate, because even with all my detours and excursions, this tutorial is incredibly short! However, I’m going to publish it as is, since you’ve all been waiting patiently while I was taking vacations and wandering around at Pycon Canada (where Kivy was mentioned both in the keynote speech and in the first talk of the day). Next week, let’s try to run this sucker on Android!

Financial Feedback

If you are enjoying this tutorial series and would like to see similar work published in the future, please support me. I dream of a future where open companies like gittip and open contributions help the world run in harmony instead of in competition. I believe that my work is high quality and worth backing. If you think this article held enough value that you would have paid for it, please consider backing me in one or more of the following ways:

Creating an Application in Kivy: Part 7

I don’t know about you, but I was pretty excited at the end of Part 6 when I was able to send a message to myself on another account. It’s taken several weeks to get here, but by the end of this part, we’ll have a [mostly|barely] working jabber client that can send and receive messages and isn’t too annoying to interact with.

If you haven’t been following along or want to start this example at the same point at which I’m starting, you can clone the github repository with my examples:

git clone https://github.com/buchuki/orkiv.git
git checkout end_part_six

Remember to create and activate a virtualenv populated with the appropriate dependencies, as discussed in part 1.

Table Of Contents

If you’ve never thought about it before, let me tell you: maintaing a table of contents on WordPress is a royal pain in the ass.

  1. Part 1: Introduction to Kivy
  2. Part 2: A basic KV Language interface
  3. Part 3: Handling events
  4. Part 4: Code and interface improvements
  5. Part 5: Rendering a buddy list
  6. Part 6: ListView Interaction
  7. Part 7: Receiving messages and interface fixes
  8. Part 8: Width based layout
  9. Part 9: Deploying your Kivy application

Receiving Messages

Receiving messages with SleekXMPP isn’t quite as simple as sending them, but it’s pretty damn simple! SleekXMPP has an event handler, not unlike the one Kivy provides, but don’t confuse them! SleekXMPP is running in a separate thread and doesn’t know or care that Kivy is running it’s own event loop. Further, they use different APIs, which basically means that they use different method names to accomplish similar things, like issuing an event or listening to receive one.

Thus, in order to not be confused with Kivy Events, we don’t call our handler on_message or something in that. Instead, we add a handle_xmpp_message method to the OrkivRoot class:

(commit)

def handle_xmpp_message(self, message):
    if message['type'] not in ['normal', 'chat']:
        return
    jabber_id = message['from'].bare

    if jabber_id not in self.chat_windows:
        self.chat_windows[jabber_id] = ChatWindow(jabber_id=jabber_id)
    self.chat_windows[jabber_id].chat_log_label.text += "(%s) %s: %s\n" % (
            datetime.datetime.now().strftime("%Y-%m-%d %H:%M"),
            jabber_id,
            message['body'])

When called by SleekXMPP, this method is passed a message object, which is some kind of stanza object. I didn’t bother to fully understand how this object is constructed; instead I stole some code from the SleekXMPP quickstart and then introspected it by printing stuff to the terminal when the handler is called. It can often be useful to print(dir(message)) to see what kind of attributes and methods an unknown object has. print(type(message)) can also be useful in that knowing the name of a class can help figure out where to look in the documentation or source code.

So after a wee bit of trial and error, I came up with the above method. It first checks the type, and gets the bare attribute off the jabber_id (the documentation helped here). Then, if the chat window does not exist, we create it, the exact same way we did when the user created the object. Even if the user is not currently looking at the chat, the message will show up in it. We then append the new message to the label using the same format we used when sending messages.

Now, hook up the event handler at the moment the xmpp object is constructed in the connect_to_jabber method of the Orkiv. It just takes one new line of code at the end of the method:

(commit)

    self.xmpp.add_event_handler('message', self.root.handle_xmpp_message)

We’ll make the label look a bit cleaner shortly, but first: test it! Start chatting with your jabber friends. Tell them how you’ve written your own jabber client using Python and Kivy. If they aren’t sufficiently impressed, find new friends!

Cleaning up duplicate code

There’s a couple pieces of code in our OrkivRoot and ChatWindow classes that look very similar to each other. First, the code for creating a new chat window only if one doesn’t exist is identical. And the code for formatting a new chat message and appending it to the chat log is also congruent.

It is a good idea to remove pieces of duplicate code as soon as you notice them. Duplicate code is a “code smell”; it indicates that your design is not good. From a practical point of view, it means maintenance can be difficult if you decide to change something (say the formatting of the date on a chat message) and forget to update multiple places at once. Of course right now you remember it’s in two places, but six months from now when these two classes have been refactored into separate files, you might not remember so easily.

There are a variety of patterns to remove duplicate code, and each situation can be different. The easiest thing to do is to refactor the things that stay the same into a function and pass the things that change in as arguments. Or you might be able to use object oriented programming and inheritance. Python’s decorator syntax or context managers can also be extremely useful for reducing duplicate code. The point is, as soon as you’ve hit the copy-paste key combination, you should start thinking about the most effective API that can be designed to remove redundancy.

In this case, we can just add a couple new methods, one to OrkivRoot and one to ChatWindow. Let’s start by refactoring the code that creates a chat window only if it doesn’t exist:

(commit)

    def get_chat_window(self, jabber_id):
        if jabber_id not in self.chat_windows:
            self.chat_windows[jabber_id] = ChatWindow(jabber_id=jabber_id)
        return self.chat_windows[jabber_id]

    def show_buddy_chat(self, jabber_id):
        self.remove_widget(self.buddy_list)
        self.add_widget(self.get_chat_window(jabber_id))

    def handle_xmpp_message(self, message):
        if message['type'] not in ['normal', 'chat']:
            return
        jabber_id = message['from'].bare

        chat_window = self.get_chat_window(jabber_id)
        chat_window.chat_log_label.text += "(%s) %s: %s\n" % (
                datetime.datetime.now().strftime("%Y-%m-%d %H:%M"),
                jabber_id,
                message['body'])

All we did was add a new method that gets the chat window from the dictionary, creating one if it doesn’t exist. Then we simplify the two methods that were previously performing this task to simply call that method. Those methods are now easier to follow. The basic principle is to abstract the complex code into it’s own function so that calling code is more readable.

Now let’s do the same thing for message formatting by adding a append_chat_message method to the ChatWindow class:

(commit)

    def send_message(self):
        app = Orkiv.get_running_app()
        app.xmpp.send_message(
            mto=self.jabber_id,
            mbody=self.send_chat_textinput.text)
        self.append_chat_message("Me:", self.send_chat_textinput.text)
        self.send_chat_textinput.text = ''

    def append_chat_message(self, sender, message):
        self.chat_log_label.text += "(%s) %s: %s\n" % (
                sender,
                datetime.datetime.now().strftime("%Y-%m-%d %H:%M"),
                message)

We also make a similar change to the code in OrkivRoot that handles incoming text events:

def handle_xmpp_message(self, message):
    if message['type'] not in ['normal', 'chat']:
        return
    jabber_id = message['from'].bare

    chat_window = self.get_chat_window(jabber_id)
    chat_window.append_chat_message(jabber_id, message['body'])

Interface Improvements

Let’s make some improvements to that chat window. Start by modifying the method we just added to include some color to help the reader identify who sent what. The Label class has a feature that allows you to include markup on the label. Unfortunately, it has it’s own microsyntax instead of using any standard markup languages. This is good because it allows the language to target the things that Kivy labels can do, but not so great in that you have yet another markup to learn. (My life would be much easier if I was not constantly switching between ReST, Markdown, Trac wiki syntax, Mediawiki syntax, and HTML! Except for HTML, I’ve never really been able to learn or distinguish them, so I have to look up the syntax every time I write it.)

The Kivy label syntax is reminiscent of bbcode popular on web forums, so if you’ve used that, you should be comfortable. I’m not going to go into detail of the syntax, since the documentation does a great job of that, but I will show you how to use colors and bold text to make our ChatWindow label much more eye-pleasing:

(commit)

    from kivy.utils import escape_markup  # At top of file

    def send_message(self):
        app = Orkiv.get_running_app()
        app.xmpp.send_message(
            mto=self.jabber_id,
            mbody=self.send_chat_textinput.text)
        self.append_chat_message("Me", self.send_chat_textinput.text, color="aaffbb")
        self.send_chat_textinput.text = ''

    def append_chat_message(self, sender, message, color):
        self.chat_log_label.text += "[b](%s) [color=%s]%s[/color][/b]: %s\n" % (
                datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                color,
                escape_markup(sender),
                escape_markup(message))

We added a color parameter to append_chat_message. It needs to be a hextet like HTML colors. Then we used the markup syntax to make the usernames colored and the dates and usernames bold. We also escape the message and sender strings so that users don’t get confused if they accidentally include Kivy formatting tags.

Remember to add the color parameter when calling this function from the handle_xmpp_message method on OrkivRoot:

    chat_window.append_chat_message(jabber_id, message['body'], color="aaaaff")

Finally, this won’t actually render as markup until we tell the label that we want markup rendered. This can be done easily by setting the markup property on the label in the KV Language file:

    Label:
        markup: True
        id: chat_log_label

Now if you run the program and chat with someone, you can easily distinguish who said what! However, if your chat gets too long, it gets truncated, both horizontally and vertically. Let’s make it scroll using a Kivy ScrollView. This can be done entirely in orkiv.kv, though it’s not trivial to get it right:

(commit)

    ScrollView:
        Label:
            size_hint_y: None
            text_size: (root.width, None)
            size: self.texture_size
            markup: True
            id: chat_log_label

In addition to wrapping the label in a scroll view, we also had to set a few sizing properties on the label. The size_hint_y is set to None or else the label would always be exactly the same size as the ScrollView. We want it to be bigger than the scroll view, or else there wouldn’t be anything to scroll!. In fact, we want it to be exactly the same size as the texture_size, which gets updated whenever lines get added to the Label. Finally, to make the lines wrap (because we don’t want to do ugly horizontal scrolling), we set the text_size to have the same width as the parent.

This can be a bit confusing, so let me explain, hopefully correctly (I’m a bit confused, myself, to be honest). First, we have a ScrollView which does not have an explicit size, so it’s size is set for us by the parent BoxLayout. The ScrollView contains a Label, which contains a Texture. The height of the label is set to be the height of the texture, which is calculated from the number of lines being displayed, and updated dynamically. Further, the width of the text rendered on the texture is constrained to be the width of the root widget, which forces the text to wrap. When the text wraps, the texture size gets bigger, and the label gets bigger because it’s bound to the texture size. and the size of the label can be as big as it wants since it’s scrollable.

These changes have the side effect of left-aligning chat, which I was expecting to have to do manually. Go Kivy! One more thing I want to do is scroll the window to the bottom if there’s any new text. This is easily done by adding a single line to the append_chat_message method:

(commit)

    def append_chat_message(self, sender, message, color):
        self.chat_log_label.text += "[b](%s) [color=%s]%s[/color][/b]: %s\n" % (
                datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                color,
                escape_markup(sender),
                escape_markup(message))
        self.chat_log_label.parent.scroll_y = 0.0

The scroll_y attribute on ScrollView is basically a percentage. it returns the current scroll position if you get it, and if you set it, it will scroll the window; 0 is the bottom, 1 is the top, and anything in between is… well, anything in between.

Now I’d like to have the form send a message on an enter keypress, not just when I click the button. This has been annoying me in testing this app and annoyances should be addressed. We can use the same technique we used in part 4. However, instead of hard-coding a call when the enter key is pressed, let’s create a new reusable widget that fires an event when enter is pressed. We’ve had quite a bit of experience binding functions to events, but we haven’t yet tried creating an event of our own.

We’ll call the new widget EnterTextInput. Binding and dispatching events is actually surprisingly simple, so our new class is pretty short:

(commit)

class EnterTextInput(TextInput):
    def __init__(self, **kwargs):
        self.register_event_type("on_enter_key")
        super(EnterTextInput, self).__init__(**kwargs)

    def _keyboard_on_key_down(self, window, keycode, text, modifiers):
        if keycode[0] == 13:  # 13 is the keycode for <enter>
            self.dispatch("on_enter_key")
        else:
            super(EnterTextInput, self)._keyboard_on_key_down(
                    window, keycode, text, modifiers)


    def on_enter_key(self):
        pass

We explicitly register the new event type with the EventDispatcher, which is a superclass of Widget (and therefore, a superclass of TextInput) and provides the methods associated with dispatching events. Then we use a super() call to do the parent initialization.

Next, we override _keyboard_on_key_down, just as we did in the AccountDetailsTextInput class. If the user pressed enter, we dispatch our custom event; otherwise we just let the superclass do it’s thing.

Now we have to hook up that event. I want to do that on the ChatWindow text entry, but first, let’s remove some more code duplication. You might not have noticed, but when I created the _keyboard_on_key_down method above, I copy-pasted some code from the AccountDetailsTextInput. It turns out we can make our AccountDetailsTextInput class extend the new code to reduce code duplication. That means if we make any improvements to the EnterTextInput class in the future, the subclass will get them for free. Here’s the new version of AccountDetailsTextInput:

(commit)

    class AccountDetailsTextInput(EnterTextInput):
        next = ObjectProperty()

        def _keyboard_on_key_down(self, window, keycode, text, modifiers):
            if keycode[0] == 9:  # 9 is the keycode for <tab>
                self.next.focus = True
            else:
                super(AccountDetailsTextInput, self)._keyboard_on_key_down(
                        window, keycode, text, modifiers)

        def on_enter_key(self):
            self.parent.parent.parent.login()  # this is not future friendly

Basically, we just removed the code for dealing with the enter key and add an event handler that does the same thing when the enter key is pressed. It’s a simple refactor, and arguably isn’t terribly more readable than the original version. However, it is more maintainable. For example, if in the future we discover that an enter key can generate different keycodes in different countries, we only have to fix it in one place.

Now let’s also hook up the new event on our ChatWindow in the KV language file. Change the TextInput to a EnterTextInput and hook up the new event:

(commit)

    EnterTextInput:
        id: send_chat_textinput
        on_enter_key: root.send_message()

That’s much better! However, there’s still a bit to be desired in terms of notifications. Let’s make Kivy play a sound whenever a message comes in! I grabbed a creative commons sound (attributed to User TwistedLemon) from Free sound and saved it as orkiv/sounds/in.wav. You can also steal a sound from your favourite IM program or record something yourself. Playing the sound is as easy as loading it in the OrkivRoot initializer:

(commit)

from kivy.core.audio import SoundLoader  # At top of file

    self.in_sound = SoundLoader.load("orkiv/sounds/in.wav")

And playing it in the handle_xmpp_message method:

    self.in_sound.play()

We’re running a bit short on space for this week, but there’s one more thing I’d like to do. Right now, when we receive a notification, it’s impossible to know who sent the message, unless we currently have that chat window open. Let’s make our BuddyList highlight those users who have new messages.

The plan I have for this is not the best plan, as it doesn’t clearly separate data from display. We’re adding a new piece of data for each jabber_id (whether or not it has new messages), but instead of creating a proper data model, I’m just going to store that data in a set. Remember, the args_converter is drawing data from the xmpp presence and other locations, and the attribute of whether something is selected is stored in the state of the BuddyListItem, so in some ways, the args_converter IS a data model.

It’s not elegant. However, making it elegant requires both that the ListView API be properly designed, and that we stop abusing it to take only the parts we want. So let’s go with simple for now!

Start by adding an attribute to the BuddyList.__init__ method. It will be a set object, and will contain only jabber_ids that have new messages:

(commit)

    def __init__(self):
        super(BuddyList, self).__init__()
        self.app = Orkiv.get_running_app()
        self.list_view.adapter.data = sorted(self.app.xmpp.client_roster.keys())
        self.new_messages = set()

We use a set instead of a list because sets are more efficient when we want to ask the question “is this object in the set”. We aren’t going to be doing that millions of times and the size of the set isn’t going to be tens of thousands of objects, so it’s not a really important distinction for this code. However, it’s good to get in the habit of using and knowing which data structures to use for which tasks. At some point in your programming career, you will want to study up on “Algorithms Analysis” and “Data Structures” to help you make these decisions. For now, just remember that any time you are keeping a collection of objects so you can repeatedly use the in keyword on it, use a set. Any time you need to know the order of objects, use a list.

Before we start adding messages to this set, let’s create a method on BuddyList that forces the listview to redraw itself. This method shouldn’t really be required if we were using the ListView API properly and it was working properly, but we aren’t and it’s not:

(commit)

    def force_list_view_update(self):
        self.list_view.adapter.update_for_new_data()
        self.list_view._trigger_reset_populate()

Now we need to add users to the set whenever we get a new message in handle_xmpp_message, telling the BuddyList to redraw itself as we do so:

(commit)

    if chat_window not in self.children:
        self.buddy_list.new_messages.add(jabber_id)
        self.buddy_list.force_list_view_update()

We only add the “new message” notification if the chat window is not the currently displayed one. If it is, then the new message shows up on the screen immediately, so it’s not unread.

Similarly, when the user selects a new buddy from the buddy list, we need to clear the new message status for that user:

    def show_buddy_chat(self, jabber_id):
        self.remove_widget(self.buddy_list)
        self.add_widget(self.get_chat_window(jabber_id))
        self.buddy_list.new_messages.discard(jabber_id)
        self.buddy_list.force_list_view_update()

The discard method, unlike remove does not raise an exception if the item is not in the set.

Of course, running this code won’t actually highlight anything. Knowing that the jabber_id has a new message doesn’t help us unless we do something with that knowledge. Let’s replace the background color if statement in BuddyList.roster_converter with the following:

(commit)

   if jabberid in self.new_messages:
       result['background_color'] = (0.6, 0.4, 0.6, 1)
   else:
       result['background_color'] = (0, 0, 0, 1)

   if index % 2:
       result['background_color'] = (x + .3 for x in result['background_color']) 

Basically, if it’s a new message, we give it a new color. But then, to maintain the alternating colors of list items, we add 0.3 to the colors in every other row. Overall, the interface is working pretty well.

Next time, we’ll see if we can get it to render the chat window beside the buddy list, if the window is wide enough! However, please note that it’s going to be a couple weeks before I can publish that article; I’m on vacation this weekend and the following weekend I’ll be at Pycon Canada (look me up if you’re there!).

Monetary feedback

While, in previous parts of this tutorial, I’ve been soliciting funds to support my continued involvement in writing and open source projects, this week, I’m going to ask you to fund Mathieu Virbel instead. Mathieu is the inventor and (utterly brilliant) lead developer of Kivy. The more time he can spend developing Kivy, the better it is for all of us (including me)!

Of course, you’re also welcome to tip me instead, or any of the other wonderful members of the Kivy team.

Or just promote Kivy and my books and articles on your favourite social media platforms. Spread the word, it’s always appreciated!

Creating an Application in Kivy: Part 6

Welcome back, or if you’ve just stumbled across this tutorial, welcome to the middle of something! You might want to jump back to the beginning if that’s the case. Don’t worry, we’ll wait for you to catch up.

We’re learning Kivy by developing a simple chat application together on the XMPP protocol. So far we’re able to display a Buddy List that doesn’t look too shabby, but we haven’t even tried chatting with anyone yet. Given the complexities of the sleekxmpp library, I’m only hoping that it won’t be too difficult!

If you want to start this part with a clean slate, in exactly the state that I’m starting it, you can clone my public repository:

git clone https://github.com/buchuki/orkiv.git
git checkout end_part_five

Remember to create and activate a virtualenv populated with the appropriate dependencies, as discussed in part 1.

Table Of Contents

Here’s some lovely navigation for you:

  1. Part 1: Introduction to Kivy
  2. Part 2: A basic KV Language interface
  3. Part 3: Handling events
  4. Part 4: Code and interface improvements
  5. Part 5: Rendering a buddy list
  6. Part 6: ListView Interaction
  7. Part 7: Receiving messages and interface fixes
  8. Part 8: Width based layout
  9. Part 9: Deploying your Kivy application

About The Current Kivy ListView API

I’m afraid this article’s going to be going up a little late because I’ve spent a great deal of time trying to understand the ListView API for interacting with the user. I’ve read through all the documentation, I’ve read through all the examples included with Kivy, and I’ve read through the source code for all the views, adapters, and widgets. I’ve come to the conclusion that, unlike the elegance in most of Kivy, the ListView API simply sucks. I think my favorite aspect of the documentation was the statement, “Warning: This code is still experimental, and its API is subject to change in a future version.”

I did discover that Kivy’s ListView API provides all the tools to do what we want, but it’s mixed in with a whole bunch of tools that don’t work at all, don’t work the way you would expect, or are far more complicated than necessary. Figuring out which of those tools to use and how to use them was a perfect chance to practice skills for dealing with frustration.

The good news is that when I complained about the ListView API on the #kivy IRC channel I was told that the developers are already actively working on improving it!

I have tried, in these tutorials, to explain not only how to do things, but also how to figure out how to do things. I’m not going to do that for this part for a few reasons. First, there is no clear explanation on the web for “how to effectively use Kivy’s ListView API”, so I’d like this tutorial to fill that niche. Second, with the API redesign in the works, I don’t want to spend a lot of time writing outdated content. Third, the approach I used to understand the API was basic brute force, and not educational in any way. Read all the documentation, read all the sources, and write tons of test code. By trial and error and a bit of good judgment, I think you’ll come to the same conclusions I did. Finally, I spent so much time doing that brute force work that I can’t easily summarize the steps I followed or all the paths I explored.

How to Ignore Most of The Bad Bits

I’m sure you’re aching to see some code, but let’s discuss exactly what we want the interface to look like, first. While our BuddyListItem widget contains several other widgets, we want it to highlight the entire widget with a different background color when it is touched. Essentially, even though multiple items are being displayed on the widget, we want the whole widget to behave like a button. Later, we’ll want to pop up a chat window when the selection event happens.

That “behave like a button” line is the key. The Button class inherits from label and adds some things for button state and touch events. Then Kivy extends that with a ListItemButton class that manages the state of multiple buttons in a ListView. As the Kivy examples show, using this class as the cls argument to a ListView works flawlessly. You touch a button, it gets highlighted. Unfortunately, adding widgets to a button doesn’t work so well because Button is not a layout. If only we could make our BuddyListItem a button AND a layout. Hmmm:

(commit)

from kivy.uix.listview import ListItemButton  # At top of file

class BuddyListItem(BoxLayout, ListItemButton):
    jabberid = StringProperty()
    full_name = StringProperty()
    status_message = StringProperty()
    online_status = StringProperty()
    background = ObjectProperty()

This is multiple inheritance; BuddyListItem is inheriting from both the BoxLayout and ListItemButton superclasses. I honestly did not expect this to work with widgets, since the inheritance graph is a weird diamond. However, the Kivy devs have been careful to support multiple inheritance (by always passing **kwargs to super calls). When I ran this code and saw selectable buttons in my ListView, I said to myself, “Holy shit! It works!” Then I giggled softly and promptly forgave the Kivy team for the confusing API faux pas.

Now we get to do one of my favorite activities: Deleting code. One of the nice things we inherit from the Button class is a background_color property. This means we can take the entire canvas.before section out of orkiv.kv:

(commit)

<BuddyListItem>:
    size_hint_y: None
    height: "75dp"

    BoxLayout:
        size_hint_x: 3
        orientation: 'vertical'
        Label:
            text: root.jabberid
            font_size: "25dp"
            size_hint_y: 0.7
        Label:
            text: root.status_message
            color: (0.5, 0.5, 0.5, 1.0)
            font_size: "15dp"
            size_hint_y: 0.3
    Label:
        text: root.full_name
    Image:
        source: "orkiv/icons/" + root.online_status + ".png"

Nothing new here at all, it’s just shorter! You can also remove the background property from __main__.py. Now, just change the arg_converter to set background_color instead of background and the button will look less buttony and more listitemy:

(commit)

if index % 2:
    result['background_color'] = (0, 0, 0, 1)
else:
    result['background_color'] = (0.05, 0.05, 0.07, 1)

Finally, I’m not too keen on the default red color for the selected item, so let’s change the selected_color (this is a property available on ListItemButton) in the Kivy file:

(commit)

<BuddyListItem>:
    size_hint_y: None
    height: "75dp"
    selected_color: (0.2, 0.1, 0.2, 1.0)

Run this code and you should be able to touch any list item and see it highlighted. Now that’s what I call an easy way to display selected items on a ListView! Don’t take these as gospel, since your needs may differ, but here’s some ideas that I came up with while puzzling through the documentation and code for this API:

  • Don’t use DictAdapter. As far as I can tell, you can more easily use ListAdapter on the keys and reference the underlying dictionary directly from args_coverter, rather than trying to maintain the sorted_keys parameter.
  • As I mentioned in Part 5 don’t use the template argument to ListAdapter, as that functionality has been deprecated.
  • Pretend that CompositeListItem does not exist, never did exist, and could not possibly exist.
  • ListItemLabel is not interactive and is for display only, not selection.
  • While the documentation suggests that you can create your own item class, if you need selection, use ListItemButton. You can either extend it and add widgets as we did here, or put individual buttons inside another view, depending on your requirements.
  • If you don’t use ListItemButton and you need selection, you need to make sure your object provides a on_release event, since that is what ListView is hardcoded to trigger selection on.
  • propagate_selection_to_data and SelectableDataItem add a lot of complexity and are only worth it if you really know they are worth it. Don’t “avoid them at all costs”, but make sure you really need them before trying.

Designing a Chat window

I have an exercise for you that I don’t think you’ll have any trouble with if you’ve followed the previous parts of this series. Of course, I’ll provide examples and explanations shortly if you get stuck.

Here’s the exercise: Create an empty new ChatWindow class that extends BoxLayout. Style the class in the KV language so that it contains a vertical box layout holding a label identifying the user you are chatting with, a second label containing the text of the conversation, and a horizontal box layout containing a Button to return to the buddy list, a TextInput and a second Button to send chat text. Try to figure out which of these widgets need to have an id in the KV Language file hooked up to an ObjectProperty in the python file. Finally, ensure the widgets have appropriate size and size_hint properties to look reasonable.

Here’s how my ChatWindow code turned out:

(commit)

class ChatWindow(BoxLayout):
    jabber_id = StringProperty()
    chat_log_label = ObjectProperty()
    send_chat_textinput = ObjectProperty()    

And here’s my first attempt at styling. It’s a compliment to Kivy’s simplicity and elegance that when I actually hooked up the events to display this code, it looked exactly like I expected it to:

(commit)

    <ChatWindow>:
        orientation: "vertical"
        chat_log_label: chat_log_label
        send_chat_textinput: send_chat_textinput
        Label:
            text: "chatting with " + root.jabber_id
            size_hint_y: None
            height: "40dp"
        Label:
            id: chat_log_label
        BoxLayout:
            size_hint_y: None
            height: "50dp"
            Button:
                size_hint_x: None
                width: "70dp"
                text: "Buddies"
            TextInput:
                id: send_chat_textinput
            Button:
                size_hint_x: None
                width: "70dp"
                text: "Send"

Now we need an event to display a ChatWindow when a user makes a selection. Kivy’s ListView API has the ability to propagate selection events to the adapter and even the model behind the adapter. However, it’s rather involved and I suggest avoiding it unless you actually have a reason to store the advanced selection stuff. Unfortunately, this means you can’t listen to the adapter’s on_selection_change event.

However, for our use case, all we really want to do is show the chat window if the user touches an item in the list. Hence, we just need to listen for a touch event on the BuddyListItem (which extends Button and therefore has all of Button‘s events) and react to that.

The reaction will be to display a new ChatWindow object on the root. This means adding a new method to OrkivRoot:

(commit)

def show_buddy_chat(self, jabber_id):
    self.remove_widget(self.buddy_list)
    chat_window = ChatWindow(jabber_id=jabber_id)
    self.add_widget(chat_window)

When called, this code will simply clear the window and display a new, empty chat window in it’s place. One thing I may not have mentioned before is how ChatWindow accepts jabber_id as a keyword argument, even though there is no __init__ method that sets the argument. This is because Kivy automatically maps keyword arguments to Property objects on the class or any parent classes, whether we defined those properties in our code or they were defined by the Kivy widget itself.

Now all we have to do is hook up the on_release event on the BuddyListItem in the KV Language file. Note that if you are doing more complicated selection, you may want to hook up an on_state handler instead. It will be called whenever the state property changes (for selection or deselection).

While we’re at it, we can also add a similar event to render the buddy list again when the Buddies button is clicked inside the ChatWindow:

(commit)

<BuddyListItem>:
    size_hint_y: None
    height: "75dp"
    selected_color: (0.2, 0.1, 0.2, 1.0)
    on_release: app.root.show_buddy_chat(self.jabberid)

and

    Button:
        size_hint_x: None
        width: "70dp"
        text: "Buddies"
        on_release: app.root.show_buddy_list()

Now, if we run the app, we can switch between the buddy list and a chat view whenever we want. This will be useful for a phone-sized layout, and in a later tutorial we’ll make it possible to switch to a side-by side view for tablets and desktops.

However, this isn’t an optimal code design. First, it’s wasteful of resources; each time, we go back to the Buddy List view, the list is constructed afresh, from scratch. Worse, new chat windows are also constructed each time we go back to a jabberid, meaning that any previous conversation would be lost. Let’s fix both these things in the OrkivRoot class:

(commit)

class OrkivRoot(BoxLayout):
    def __init__(self):
        super(OrkivRoot, self).__init__()
        self.buddy_list = None
        self.chat_windows = {}

    def show_buddy_list(self):
        self.clear_widgets()
        if not self.buddy_list:
            self.buddy_list = BuddyList()
        for buddy_list_item in self.buddy_list.list_view.adapter.selection:
            buddy_list_item.deselect()
        self.add_widget(self.buddy_list)

    def show_buddy_chat(self, jabber_id):
        self.remove_widget(self.buddy_list)
        if jabber_id not in self.chat_windows:
            self.chat_windows[jabber_id] = ChatWindow(jabber_id=jabber_id)
        self.add_widget(self.chat_windows[jabber_id])

We added an initializer that sets a couple variables for us. In the show_buddy_list method, we now instantiate the BuddyList only if it has not been previously created. However, this means that selection is kept between calls, so we have to loop over the selected items and deselect them.

This might need some explaining. The ListView doesn’t know anything about selection; that is kept track of in the ListAdapter. The selection property is a list containing all BuddyListItem objects that are currently selected. Because BuddyListItem is a ListItemButton, which provides the SelectableView, interface, it has a deselect method that we can use to disable selection of that item.

The chat_windows dictionary maps jabber_id keys to individual ChatWindow objects, any of which can be displayed when the associated user is touched in the buddy list.

Sending a Message

Ok, now that our chat text box is looking pretty sweet and we can switch between buddies at will, let’s try actually sending a message! Add a new method, send_message to the ChatWindow widget in __main__.py:

(commit)

    import datetime  # At top of file

    def send_message(self):
        app = Orkiv.get_running_app()
        app.xmpp.send_message(
            mto=self.jabber_id,
            mbody=self.send_chat_textinput.text)
        self.chat_log_label.text += "(%s) Me: %s\n" % (
                datetime.datetime.now().strftime("%Y-%m-%d %H:%M"),
                self.send_chat_textinput.text)
        self.send_chat_textinput.text = ''

This is actually fairly simple code considering how exciting it is to send a message and have it show up on a different account when we run it. First we get the app and instruct the xmpp object to send a message. I got this code from the SleekXMPP documentation. Then, while that message is finding it’s way to our other chat client, we update the chat_log_label text so that it contains a new line with the current date and the text we sent. Finally, we update the send_chat_textinput to be empty so we can send another value right away.

Now we just need to invoke this method whenever the send button is clicked. I’m sure you can figure out how to do that by yourself. It’s just one line of code in the Kv Language file:

(commit)

    Button:
        size_hint_x: None
        width: "70dp"
        text: "Send"
        on_release: root.send_message()

Now for the fun part. If you have two different jabber accounts, connect your normal instant messenger to one of them, and then log into Orkiv with the other one. Send a message to the “normal” messenger and giggle manically when it arrives. This is why we program: the success is so tangible!

And I’ll leave you with that success for today. In the next part, we’ll hook up the message receiving side of things and make several interface improvements to make the app much more usable.

Monetary feedback

In previous parts of this tutorial, I’ve asked users to support me financially if they’d like to see more of it. I’m trying to gauge whether it is feasible for me to consider switching from full time work to being supported entirely by open source development, writing, and education in the (far) future.

Instead, today, I’d like to take some time to thank those of you who have answered my call. It’s impossible to tell how many book sales come from readers if these essays, or how many Gittips were prompted by this work rather than my various other open source projects, but as both have increased in the weeks that I’ve been publishing this series, it’s clear that some of you support my work. I would like to thank you from the bottom of my heart. I truly believe that an economy based on paying what the buyer, rather than the seller, thinks something is worth, will one day lead to a happier, more peaceful world.

I’d also like to thank all of you who have tweeted, commented, blogged, or otherwise spread the word about these articles. I think they are one of the best available resources for new Kivy developers outside of the excellent Kivy documentation itself. I am exhilarated to know that so many of you agree!

Creating an Application in Kivy: Part 5

In Part 4, we took a break from developing Kivy interfaces and focused on improving the interface we already had. In this part, we’ll get back to interface development by creating a widget to display the buddy list. Here’s the plan: we’ll start with a new widget to render the information we’re getting from the roster. Then we’ll figure out how to query sleekxmpp to get additional information about the user, such as their online status and status message.

If you haven’t been following along or want to start with a clean slate, you can clone the state of the example repository as of the end of part 4:

git clone https://github.com/buchuki/orkiv.git
git checkout end_part_four

Remember to create and activate a virtualenv populated with the appropriate dependencies, as discussed in part 1.

Table Of Contents

If you’re just joining us, you might want to jump to earlier steps in this tutorial:

  1. Part 1: Introduction to Kivy
  2. Part 2: A basic KV Language interface
  3. Part 3: Handling events
  4. Part 4: Code and interface improvements
  5. Part 5: Rendering a Buddy List
  6. Part 6: ListView Interaction
  7. Part 7: Receiving messages and interface fixes
  8. Part 8: Width based layout
  9. Part 9: Deploying your Kivy application

Rendering A Basic ListView

So far, after successful login, a list of usernames is printed on the ConnectionModal popup. That’s not quite what we want to do. Rather, we want to dismiss the popup and render the buddy list in the root window instead of the login form.

The first thing we’ll have to do here is wrap the login form in a new root widget. We should have done this from the start, but to be honest, I didn’t think of it. This widget will be a sort of manager for the AccountDetailsForm, BuddyList, and ChatWindow. If we only ever wanted to show one window at a time, we could use Kivy’s ScreenManager class to great effect. However, I hope to display widgets side by side if the window is wide enough, so let’s try coding it up manually.

First we can add an OrkivRoot (leaving it empty for now) class to __main__.py. Let’s add a BuddyList class while we’re at it, since we’ll need that shortly.

(commit)

from kivy.uix.boxlayout import BoxLayout  # at top of file

class BuddyList(BoxLayout):
    pass


class OrkivRoot(BoxLayout):
    pass

Next, we update the orkiv.kv to make OrkivRoot the new root object (replacing the current AccountDetailsForm: opening line) and make any instances of OrkivRoot contain an AccountDetailsForm:

(commit)

OrkivRoot:

<OrkivRoot>:
    AccountDetailsForm:

Now let’s add a show_buddy_list method to the OrkivRoot class. This method will simply clear the contents of the widget and construct a new BuddyList object for now:

(commit)

class OrkivRoot(BoxLayout):
    def show_buddy_list(self):
        self.clear_widgets()
        self.buddy_list = BuddyList()
        self.add_widget(self.buddy_list)

And finally, we can remove the temporary code that renders buddy list jabberids on the ConnectionModal label and replace it with a call to show_buddy_list:

(commit)

def connect_to_jabber(self):
    app = Orkiv.get_running_app()
    try:
        app.connect_to_jabber(self.jabber_id, self.password)
        app.root.show_buddy_list()
        self.dismiss()

Note that we also explicitly dismiss the ConnectionModal. The new BuddyList widget, which is currently blank, will be displayed as soon as we have a valid connection.

Let’s add some styling to that BuddyList class in our orkiv.kv file. We’ll add a ListView which provides a scrollable list of widgets. Of course, we’re not actually putting anything into the ListView, so if we run it now, it won’t show anything… but it’s there!

(commit)

<BuddyList>:
    list_view: list_view
    ListView:
        id: list_view

Notice that I gave the ListView an id property and connected it to a list_view property on the root widget. If you remember part 3 at all, you’re probably expecting to add an ObjectProperty to the BuddyList class next. You’re right!

(commit)

class BuddyList(BoxLayout):
    list_view = ObjectProperty()

    def __init__(self):
        super(BuddyList, self).__init__()
        self.app = Orkiv.get_running_app()
        self.list_view.adapter.data = sorted(self.app.xmpp.client_roster.keys())

Since you guessed that ObjectProperty was coming, I added an initializer as well. I have to keep you interested, after all! The initializer first sets up the superclass, then sets the list_view‘s data to the buddy list keys we’ve been using all along. There’s a couple complexities in this line of code, though. First note the call to sorted, which accepts a python list (in this case containing the ids in the buddy list) and returns a copy of the list in alphabetical order. Second, we are setting the list_view.adapter.data property. Underneath the hood, ListView has constructed a SimpleListAdapter for us. This object has a data property that contains a list of strings. As soon as that list is updated, the adapter and ListView work together to update the display.

The reason that the data is stored in an adapter is to separate the data representation from the controller that renders that data. Thus, different types of adapters can be used to represent different types of data. It’s possible to construct your own adapter as long as you implement the relevant methods, but this is typically unnecessary because the adapters that come with Kivy are quite versatile.

Try running this code. Upon successful login, the modal dialog disappears and the buddy list pops up in sorted order. Resize the window to be smaller than the list and you can even see that the ListView takes care of scrolling.

The SimpleListAdapter is not sufficient for our needs. We need to be able to display additional information such as the user’s status and availability, and we want to lay it out in a pretty way. We’ll also eventually want to allow selecting of a Buddy in the list so we can chat with them. SimpleListAdapter supports none of this. However, Kivy’s ListAdapter does. So let’s edit the orkiv.kv to use a ListAdapter for the BuddyList class:

(commit)

# at top of file:
#:import la kivy.adapters.listadapter  # at top of file
#:import lbl kivy.uix.label

<BuddyList>:
    list_view: list_view
    ListView:
        id: list_view
        adapter: la.ListAdapter(data=[], cls=lbl.Label)

First, we import the listadapter module using the name la. This has a similar effect to a from kivy.adapters import listadapter as la line in a standard Python file. This #:import syntax can be used to import any python module that you might need inside the kv language file. The syntax is always #:import <alias> <module_path>. However, you can only import modules, you can’t import specific classes inside modules. This is why I used a rather uninformative variable name (la). When we construct the ListAdapter at the end of the snippet, the shortened form happens to be more readable, since we are immediately following it by a class name.

We also import the label class as lbl. While it seems odd to have to import Label when we have seen Label used in other parts of the KVLanguage file, we have to remember that sometimes KV Language allows us to switch to normal Python. That’s what’s happening here; the code after adapter: is normal python code that doesn’t know about the magic stuff Kivy has imported. So we have to import it explicitly.

This is probably not the best way to do this; we’re probably going to have to replace this view with a custom ListView subclass later, but it suits our needs for the time being.

That code is simply constructing a new ListAdapter object. It assigns empty data (that will be replaced in BuddyList.__init__) and tells the ListAdapter that the cls to render the data should be a Label. So when we run this code, we see a scrollable list of Labelcode> objects each with their text attribute automatically set to one of the jabber ids we set up in the BuddyList initializer.

However, a Label still isn’t the right widget for rendering a buddy list item. We need to show more information in there, like whether they are available or away and what their status message is. A label won’t cover this, at least not cleanly, so let’s start writing a custom widget instead.

First, add a BuddyListItem class to the __main__.py:

(commit)

from kivy.properties import StringProperty  # At top of file

class BuddyListItem(BoxLayout):
    text = StringProperty()

By default, ListAdapter passes a text property into the widget that is used as its cls. So we hook up such a property which will be rendered by the label in the KV language file. This is a StringProperty, which behaves like any other property but is restricted to character content. Now we can use this class in the KV Language file:

(commit)

# at top of file:
#:import ok __main__

<BuddyListItem>:
    size_hint_y: None
    height: "100dp"
    Label:
        text: root.text

<BuddyList>:
    list_view: list_view
    ListView:
        id: list_view
        adapter: la.ListAdapter(data=[], cls=ok.BuddyListItem)

Don’t forget to make the adapter cls point at the new BuddyListItem class. You can also remove the Label import at the top.

We set a height property on the BuddyListItem mostly just to demonstrate that the custom class is being used when we run the app. Notice also how the label is referencing the root.text property we set up in the python file.

This property is being set, seemingly by magic, to the value from the data list we set on ListAdapter. In fact, it’s not magic; Kivy is just doing a lot of work on our behalf. For each string in that list, it’s constructing a new BuddyListItem object and adding it to that scrollable window. It then sets properties on that object using its default arg_converter. The arg_converter is responsible for taking an item from a data list and converting it to a dictionary of properties to be set on the cls object. The default is to simply take a string and set the text property to that string. Not so magic after all.

And now we’re going to make it less magic. Instead of a text property, let’s make a few properties that better reflect the kind of data we want to display:

(commit)

class BuddyListItem(BoxLayout):
    jabberid = StringProperty()
    full_name = StringProperty()
    status_message = StringProperty()
    online_status = StringProperty()

Don’t try running this without updating the KV file, since it’s trying to reference a text property that is no longer there:

(commit)

<BuddyListItem>:
    size_hint_y: None
    height: "40dp"
    Label:
        text: root.jabberid
    Label:
        text: root.full_name
    Label:
        text: root.status_message
    Label:
        text: root.online_status

Of course, running it in this state will bring us an empty window, since the ListAdapter is still using the default args_converter. Let’s add a new method to the BuddyList class. Make sure you’re sitting down for this one, it’s a bit complicated:

(commit)

def roster_converter(self, index, jabberid):
    result = {
        "jabberid": jabberid,
        "full_name": self.app.xmpp.client_roster[jabberid]['name']
    }

    presence = sorted(
        self.app.xmpp.client_roster.presence(jabberid).values(),
        key=lambda p: p.get("priority", 100), reverse=True)

    if presence:
        result['status_message'] = presence[0].get('status', '')
        show = presence[0].get('show')
        result['online_status'] = show if show else "available"
    else:
        result['status_message'] = ""
        result['online_status'] = "offline"

    return result

Deep breaths, we’ll explore this code one line at a time. First, the new method is named roster_converter and takes two arguments, the index of the item in the list (which we’ll ignore for now), and the jabberid coming in from the data list. These are the normal arguments for any ListAdapter args_converter in Kivy.

Next, we start constructing the result dictionary that we’ll be returning from this method. Its keys are the properties in the BuddyListItem class. It’s values, of course, will be displayed on the window.

Then we ask sleekxmpp to give us presence information about the user in question. This is not a trivial piece of code. I don’t want to spend a lot of time on it, since it involves ugly Jabber and sleekxmpp details, and our focus is on Kivy. In fact, you can skip the next paragraph if you’re not interested.

First, sleekxmpp’s client_roster.presence method returns a dictionary mapping connected resources to information about that resource. For simplicity, we’re ignoring resources here, but the basic idea is that you can be connected from two locations, say your cell phone and your laptop, and you’ll have two sets of presence information. Since we don’t care about resources, we ignore the keys in the dictionary and ask for just the values(). However, we still need to pick the “most important” resource as the one that we want to get presence information from. We do this by wrapping the list in the sorted function. Each resource has an integer priority, and the highest priority is the resource we want. So we tell the sorted function to sort by priority, passing it a key argument that gets the priority using a lambda function. The function defaults to 100 if the resource doesn’t specify a priority; thus we prefer an empty priority over any other value. The reversed keyword puts the highest priority at the front of the list.

Seriously, I hope you skipped that, because it’s a lot of information that is not too pertinent to this tutorial, even if the code it describes is. It took me a lot of trial and error to come up with this code, so just be glad you don’t have to!

So, assuming a list of resources is returned for the given jabber id, we pick the front one off the list, which is the one deemed to have highest priority. We then set the status_message directly from that item, defaulting to an empty string if they user hasn’t set one. The show key in this dict may return the empty string if the user is online (available) without an explicit status, so we check if the value is set and default to “available” if it is not.

However, there’s a chance that call returns a completely empty list which tells us what?: That the user is not online. So we have that else clause constructing a fake presence dict indicating that the user is offline.

Finally, things become simple again. We return the constructed dictionary that maps property names to values, and let Kivy populate the list for us. All we have to do for that to happen is tell Kivy to use our custom args_converter instead of the default one. Change the adapter property in the KV Language file to:

(commit)

adapter:
    la.ListAdapter(data=[], cls=ok.BuddyListItem,
    args_converter=root.roster_converter)

Notice that I split the command into two lines (indentation is important, if a bit bizarre.) in order to conform to pep 8‘s suggestion that line length always be less than 80 characters.

Now, finally, if you run this code and login, you should see all the information about your buddies pop up! However, it’s still a wee bit ugly. Let’s find some ways to spice it up.

One simple thing we can do is highlight different rows by giving each one a background color. We can start by adding a background attribute as an ObjectProperty to the BuddyListItem. Then we can set this value inside the roster_converter:

(commit)

if index % 2:
    result['background'] = (0, 0, 0, 1)
else:
    result['background'] = (0.05, 0.05, 0.07, 1)

Remember that index parameter that is passed into all args_converters and we were ignoring. Turns out it comes in handy. We can take the modulo (that’s the remainder after integer devision if you didn’t know) 2 of this value to determine if it’s an even or odd numbered row. If it’s odd (the remainder is not zero), then we set the background to black. Otherwise, we set it to almost black, a very deep navy. The background color is set as a tuple of 4 values, the RGBA value (Red, Green, Blue, Alpha). Each of those takes a float between 0 and 1 representing the percentage of each of those to add to the color.

Now, most Kivy widgets don’t have a background attribute, so we’re going to have to draw a full screen rectangle on the widget’s canvas. This is great news for you, because we get to cover the canvas or graphics instructions, something this tutorial has neglected so far. The canvas is a drawing surface that accepts arbitrary drawing commands. You can think of it as lower level than widget, although in reality, widgets are also drawn on the canvas, and every widget has a canvas. Here’s how we set up a rectangle on the BuddyListItem canvas:

(commit)

canvas.before:
    Color:
        rgba: self.background
    Rectangle:
        pos: self.pos
        size: self.size

I put this code above the labels in the BudyListItem. The canvas.before directive says “issue this group of commands before painting the rest of the widget”. We first issue a Color command, setting its rgba attribute to the 4-tuple we defined as the background. Then we issue a Rectangle instruction, using the currently set Color and setting the position and size to be dynamically bound to the size of the window. If you resize the window, the rectangle will be automatically redrawn at the correct size.

Another thing I want to do to improve the interface is render status messages underneath the username. They could go in a smaller font and maybe different color. This can be done entirely in KV Language:

(commit)

<BuddyListItem>:
    size_hint_y: None
    height: "75dp"
    canvas.before:
        Color:
            rgba: self.background
        Rectangle:
            pos: self.pos
            size: self.size
    
    BoxLayout:
        size_hint_x: 3
        orientation: 'vertical'
        Label:
            text: root.jabberid
            font_size: "25dp"
            size_hint_y: 0.7
        Label:
            text: root.status_message
            color: (0.5, 0.5, 0.5, 1.0)
            font_size: "15dp"
            size_hint_y: 0.3
    Label:
        text: root.full_name
    Label:
        text: root.online_status

I changed the height of the rows to be more friendly. The canvas I left alone, but I added a BoxLayout around two of the labels to stack one above the other in a vertical orientation. I made this BoxLayout 3 times as wide as the other boxes in the horizontal layout by giving it a size_hint_x. The two labels also get size hints, font size, and a color.

When we run this it looks… a little better. Actually, it still looks like ass, but this is because of my incompetence as a designer and has nothing to do with Kivy!

Now one more thing I’d like to do is render a status icon instead of the text “available”, “offline”, etc. Before we can do that, we need some icons. I wanted something in the public domain since licensing on this tutorial is a bit hazy. A web search found this library and I found some public domain icons named circle_<color> there. I grabbed four of them using wget:

(commit)

cd orkiv
mkdir icons
wget http://openiconlibrary.sourceforge.net/gallery2/open_icon_library-full/icons/png/48x48/others/circle_green.png -O icons/available.png
wget http://openiconlibrary.sourceforge.net/gallery2/open_icon_library-full/icons/png/48x48/others/circle_grey.png -O icons/offline.png
wget http://openiconlibrary.sourceforge.net/gallery2/open_icon_library-full/icons/png/48x48/others/circle_yellow.png -O icons/xa.png 
wget http://openiconlibrary.sourceforge.net/gallery2/open_icon_library-full/icons/png/48x48/others/circle_red.png -O icons/away.png

Once the files are saved, all we have to do to render them is replace the online_status label with an Image:

(commit)

    Image:
        source: "orkiv/icons/" + root.online_status + ".png"

And that’s it for part 5. I promised we would render a complete buddy list, and that’s what we’ve done! In part 6, we’ll make this list interactive. Until then, happy hacking!

Monetary feedback

If you are enjoying this tutorial and would like to see similar work published in the future, please support me. I plan to one day reduce the working hours at my day job to devote more time to open source development and technical writing. If you think this article was valuable enough that you would have paid for it, please consider supporting me in one or more of the following ways:

Finally, if you aren’t in the mood or financial position to help fund this work, you can always share it on your favorite social platforms.

Creating an Application in Kivy: Part 4

You know, when I was doing my planning, I expected Part 3 of this tutorial to get us all the way to rendering a window containing the buddy list. So it’s somewhat amusing that this time, I don’t expect to be at that state at the end of this part. Instead, I want to focus on a few problems and annoyances with the existing code. Never fear, though, we’ll definitely be back to coding Kivy interfaces in Part 5!

In this part, we’ll focus on fixing a problem with the interface, handling errors on login, and taking care of that need to call “disconnect” on the xmpp object after displaying the buddy list. Be forewarned however! You may also encounter digressions on version control, debugging, and testing.

If you’ve gotten lost or want to jump in without doing the previous tutorials, you can start from the example repository as of the end of part 3:

git clone https://github.com/buchuki/orkiv.git
git checkout end_part_three

Table Of Contents

Here are links to other parts of this tutorial.

  1. Part 1: Introduction to Kivy
  2. Part 2: A basic KV Language interface
  3. Part 3: Handling Events
  4. Part 4: Code and Interface Improvements
  5. Part 5: Rendering a Buddy List
  6. Part 6: ListView Interaction
  7. Part 7: Receiving messages and interface fixes
  8. Part 8: Width based layout
  9. Part 9: Deploying your Kivy application

Handling tab and enter events on text input

When I was testing the interface in part 2, I found that I naturally wanted to tab from one textfield to another, a common paradigm for desktop interfaces. Most desktop oriented toolkits have built-in support for what they call “tab order”; the order in which focus switches from one field to another when the tab key is pressed. Kivy doesn’t supply any tools for this. I think this highlights both Kivy’s emphasis on keeping a simple API and the fact that a lot of it was designed to work with mobile devices, which typically interact by touch and have neither physical keyboards nor a tab key. However, that doesn’t mean we can’t tab between our fields, it just means we have to do a bit more legwork.

Legwork generally starts with a web search. Lately, I wonder if I shouldn’t exercise my brain to come up with a solution on my own before turning to a search engine. However, deadlines are always tight, and Stack Overflow so often has an answer. Now, the code provided there doesn’t work quite the way I want it to, but it does tell us how to move forward in solving this task. Let’s get our hands dirty. We can start by adding a new class to our __main__.py:

(commit)

from kivy.uix.textinput import TextInput  # At the top

class AccountDetailsTextInput(TextInput):
    next = ObjectProperty()

    def _keyboard_on_key_down(self, window, keycode, text, modifiers):
        if keycode[0] == 9:  # 9 is the keycode for 
            self.next.focus = True
        elif keycode[0] == 13:  # 13 is the keycode for 
            self.parent.parent.parent.login()  # this is not future friendly
        else:
            super(AccountDetailsTextInput, self)._keyboard_on_key_down(
                    window, keycode, text, modifiers)

Yikes! That’s a little bit more complex piece of code than we’ve seen so far. It’s a good thing it’s so short! Let’s go through each staement. We start by creating a new widget called AccountDetailsTextInput that inherits from TextInput. This means that it looks and behaves exactly like a TextInput object… because it is one! However, we modify it a bit. First, we give it a next ObjectProperty just like we did to register TextInputs as properties on the AccountDetailsForm class in Part 3. We’ll be assigning a value to this next property inside the KV Language file later.

Then we override the _keyboard_on_key_down method on TextInput. You’re probably wondering how I knew that was the method I needed to override. Admittedly, the Stack Overflow answer provided a good hint, but I also read through the Kivy source code to make sure I knew what I was overriding and how it worked. Reading through other people’s source code can be intimidating, but is is the absolute best way to understand how something works. It’s also extremely educational, especially if you come across constructs that you don’t understand and have to look them up.

If you’re not familiar with Object Oriented Programming, you might want an explanation of what “overriding” is. Basically, whenever this method is called, we want it to do something different from what would happen if the same method were called on the parent class. Specifically, we want to handle the and keypresses in a different way.

So that’s what the conditional inside the method does. It checks the keycode value to see if it is 9 or 13. I didn’t know that the keycode was a tuple, but the source code and stack overflow question both indicated that the first value stores the keycode. I do happen to know that 9 and 13 are the keycodes for tab and enter because I’ve written similar handlers before. Can you think of a way (other than the aforementioned search engine) to determine what the keycode is for a given keypress?

Instead of the conditional in the code above, you could simply do a print(keycode[0]) inside this method and hook up the appropriate KV language syntax as we’ll discuss below. When you run the program, you’d be able to see the output on the console when the tab or enter key was pressed. There’s the information you need. Run with it!

The line where we focus the next object property is pretty straightforward; we just set a boolean value on it and let Kivy take care of the details. However, the line for the enter button is a bit tricky. To be honest, I hate this line of code. It’s very fragile. It calls self.parent to get the parent of the text input, which is a GridLayout, then calls .parent on that which yelds a BoxLayout (we’re navigating up through the orkiv.kv hierarchy here), and calls parent one more time to get the AccountDetailsForm. Then we can finally call the login method on that, to do the same thing as if we had clicked the login button. Thus users can enter their details, tab to the next box, and login without lifting their hands from the keyboard!

The reason I hate this line of code is that future changes in orkiv.kv could easily break it. If we decide to insert another Layout into the mix, this line will need to have another .parent added. If we decide to remove the surrounding BoxLayout and put the GridLayout as a direct child of AnchorLayout, it will again break. Worse, if we made such a change and ran the program, we might see that the new layout looked exactly as we wanted it to, but totally forget that we needed to test the tab-order widget.

There are other ways to get access to the AccountDetailsForm and its login method, but I’m not too keen on them either. We could call Orkiv.get_running_app().root. Or we could add an ObjectProperty to the AccountDetailsTextInput and set that property to point at the magic root variable. This latter is probably the most extensible, but it means that the Kivy Language file needs to be a bit uglier. I chose to stick with the .parent notation, but to include a comment to remind me that if I look at this section of code in the future, it would be ideal if I had an insight for how to implement it more elegantly.

Finally, we have the weird else clause which covers any case where the user has presed a key other than tab or enter. In that event, we just want the parent TextInput class to do what it would normally do; display the character in the text field on the screen. So we use the super builtin and pass it first the class we want to get the parent of, and the instance of that class, namely self. This returns basically the same object as self but as if it was an instance of TextInput instead of AccountDetailsTextInput. Then when we call _keyboard_on_key_down on that class, we get the default behavior for the class.

The rather arcane syntax of super is much simpler in Python 3, where we could just call super._keyboard_on_key_down The two argument syntax is still supported, as it is necessary to support a feature called multiple inheritance. That’s something I recommend you don’t learn about too early, not because it is a particularly complicated construct, but because it is, in my opinion, much less useful than it appears and you are quite likely to misapply it!

Oy gevalt, but that was a lot of explanation for not very much code. Luckily, you can probably figure out the changes to the Kivy Language file for yourself:

(commit)

Label:
    text: "Server"
AccountDetailsTextInput:
    id: server_input
    next: username_input
Label:
    text: "Username"
AccountDetailsTextInput:
    id: username_input
    next: password_input
Label:
    text: "Password"
AccountDetailsTextInput:
    next: server_input
    password: True
    id: password_input

We did two things to each TextInput here. First, we changed it to be an instance of the new AccountDetailsTextInput and second, we added a next attribute to each of them. This next points at the id of whichever input box it makes sense to be the next in the tab order.

But what about invalid logins?

Have you tried intentionally or accidentally entering invalid account details into this form and submitting it? The application dies outright, which is neither optimal nor friendly. Users are not infallible. In fact, users can be incredibly dedicated to totally breaking your fancy interface! Let’s try to anticipate some of their mistakes and supply an error message that makes a little sense instead of just crashing.

Let me tell you up front, this turned out to be harder than I expected! I don’t want to do anything too complicated for the intended audience of this tutorial. I ended up poking around in the sleekxmpp source code quite a bit to come up with this solution. I don’t like the results, but I saved it for you on a separate git branch. Too many tutorials pretend that the solution they present to you is the obvious one; instead, I want you to see that programming is often all about exploration and backing up and trying again.

The problem with the code I linked is that it locks up the interface so it’s hard to interact with. Since nothing can happen until connection has occurred anyway, I think it will be better to pop up a window that tells the user to wait while we perform the connection.
Before I show you the code, I want to describe how I was testing it as I developing it. I performed several different tasks and changed the code until all of them were working. This was time consuming (and the reason this tutorial is a little late) and tricky. Each time I changed things, I had to go through all the tasks to make sure that fixing one problem hadn’t broken other things. Often it had, which meant I had something else to fix and test. However, at the end of this section, you’ll be able to perform all these tasks with expected results:

  • Log into my personal jabber server and see the buddy list
  • Log into a throw away google account and see the buddy list
  • Click the login button without entering any details and get an error message to try again
  • Enter credentials for a host that does not exist and get an error message to try again
  • Enter invalid credentials for the google account and get an error message to try again

Let’s start by building a Kivy Modal View widget. A ModalView essentially sits in front of the other widgets, by default taking up the whole window, though you can make it look like it’s floating on top of the interface by giving it a size. How did I know this was the widget I wanted? I didn’t. I had to search through the Kivy API library for what I wanted. I first stumbled across the Popup widget, but it has extra features that we don’t want. However, I saw that it inherits from ModalView and that’s exactly what we need.

So we’re going to create a ModalView object that notifies the user that a connection is being attempted. If the credentials are invalid, it will give them a short message and invite them to return to the login widget and try again. If they are valid, it will print the Buddy List on itself. Let’s start adding this new class to the __main__.py:

(commit)

from kivy.uix.modalview import ModalView  # At the top of the file
from kivy.uix.label import Label

class ConnectionModal(ModalView):
    def __init__(self, jabber_id, password):
        super(ConnectionModal, self).__init__(auto_dismiss=False,
            anchor_y="bottom")
        self.label = Label(text="Connecting to %s..." % jabber_id)
        self.add_widget(self.label)
        self.jabber_id = jabber_id
        self.password = password

This is similar to what we did for the AccountDetailsForm above. We create a subclass of ModalView and initialize it with a jabber_id and password. We initialize the superclass, passing in a couple of arguments to tweak the behavior. We disable auto_dismiss because we don’t want the popup to disappear until we tell it to. Otherwise, it would disappear if the user clicked on it anywhere, even though it’s still trying to connect. We also supply anchor_y because ModalView inherits from AnchorLayout. When we add a button later, we’ll want it to pop up in front of the Label at the bottom of the screen. Notice how we are constructing a user interface in Python code here and that it’s rather bulky compared to the KV Language way of constructing an interface. However, since there’s only one widget for now and a second one created dynamically, it doesn’t really make sense to style this class in the KV Language.

We then construct a Label and add it to the Layout using add_widget. We store the reference to label on self so that we can update the text later. We similarly store the jabber_id and password.

Obviously, we aren’t constructing this widget anywhere, so it’s not going to be displayed if we run the code. Let’s rewrite the login() method to pop up this window instead of trying to connect. Note that if you were developing on your own, you might want to keep a copy of the current login() code in a separate buffer because we’ll be needing to adapt it to live in this new class, soon. Or you can just check your git history to see how the login method used to look. git show HEAD^:orkiv/__main__.py will show what it looked like in the previous revision. HEAD^ says “previous revision” to git. Yes it’s arcane syntax. You can see dozens of other ways to specify which revision you want to show in the git rev-parse manual.

Anyway, let’s display that popup in the login method:

(commit)

def login(self):
    jabber_id = self.username_box.text + "@" + self.server_box.text
    modal = ConnectionModal(jabber_id, self.password_box.text)
    modal.open()

We kept the one line from the old login() method which constructs the jabber_id. But now instead of connecting, we construct a ConnectionModal widget and instruct it to open itself. If you run this, it will no longer try to connect to jabber at all. Even though the connection code still exists on the Orkiv, that method is not being called. Obviously, calling that is the next step, but lets make tweak that connect_to_jabber method first to make it inform us when it cannot connect.

I didn’t notice the need for this change until later on when I was doing my own testing, but it’ll be easier to explain if we do it now. It’s common to do this when crafting commits in git (less so in Mercurial, which is an endless source of frustration for me). Instead of committing each piece of poorly thought out code as I go, I figure out what needs to be done and then design the commits so that they tell a coherent story to anyone that reads the history. If you read through the Examples committed on the github repo you can see each scene in this story as it is played out. It is much easier for you to understand than if I had committed each of my mistaken attempts in whatever crazy order that they occurred. When crafting git history, remember that there will always be a reader of your code and try to make the most elegant story possible.

Specifically, replace the single self.xmpp.connect() line with the following four lines:

(commit)

from sleekxmpp.exceptions import XMPPError  # At the top of the file

self.xmpp.reconnect_max_attempts = 1
connected = self.xmpp.connect()
if not connected:
    raise XMPPError("unable to connect")

There are actually two fixes here. I had to scour the sleekxmpp documentation to find the reconnect_max_attempts property. Without it, the client keeps trying to connect over and over and never fails. However, if we tell it not to bother trying to reconnect at all, for some reason, it fails to connect to gmail. So we allow it to reconnect once to keep gmail happy, but not indefinitely to keep our users happy.

Second, the connect() function returns a boolean value indicating whether the connection was successful. If it’s not successful, we want to communicate to whatever method called connect_to_jabber that it was unsuccessful. So we raise an exception that, handily enough, sleekxmpp has defined in their code. When we raise an exception, execution immediately stops in this method. However, we can catch the exception in the calling code. Let’s add that calling method to the ConnectionModal class now:

(commit)

from sleekxmpp.jid import InvalidJID  # At the top of the file

def connect_to_jabber(self):
    app = Orkiv.get_running_app()
    try:
        app.connect_to_jabber(self.jabber_id, self.password)
        self.label.text = "\n".join(app.xmpp.client_roster.keys())
    except (XMPPError, InvalidJID):
        self.label.text = "Sorry, couldn't connect, check your credentials"
    finally:
        if hasattr(app, "xmpp") and app.xmpp:
            app.xmpp.disconnect()

Notice that this method is called connect_to_jabber just like the one on the Orkiv class, but this one is attached to ConnectionManager. There is no law against reusing names if it makes sense to do so, as long as they are in a different namespace (the Orkiv namespace is completely independent from the ConnectionModal namespace). In fact, if you recall the consistency rant from Part 3, you will know that it is often desirable to do so.

We have a connect_to_jabber method on the ConnectionModal class that calls a totally different connect_to_jabber method on the Orkiv class. The latter method might raise either an XMPPError or an InvalidJID error. The former is raised explicitly if connected is False; the latter is actually raised inside the sleekxmpp code. Either way, it gets propagated up to the the ConnectionModal‘s method, where we catch it using a try...except clause. We also add a finally clause that checks if an xmpp property has been added to the app and, if so, disconnects it to keep it from freezing up the app, as we discussed in Part 3.

If you would like more information on exceptions, see the Python tutorial. There’s also good coverage of Exception handling in my book, Python 3 Object Oriented Programming.

It only takes one line of code to have this connect_to_jabber called as soon as the ConnectionModal is opened. ModalView has a open event, so we just have to assign it a callable (any function or method, such as connect_to_jabber is a callable) that is called whenever that event is invoked. So hook this up as the last line of ConnectionModal‘s __init__ method:

(commit)

self.on_open = self.connect_to_jabber

There’s one more thing I want to do. When there is a failure, instead of just showing a message and forcing the user to close the app, it would be much better if they had a way to go back to the login form. Let’s add a button that allows them to try again. Clicking this button will hide the modal window and the original login form that was behind it will be visible so the user can edit the details. This can be done by replacing the contents of the except clause with the following code:

(commit)

from kivy.uix.button import Button  # At top of file

self.label.text = "Sorry, couldn't connect, check your credentials"
button = Button(text="Try Again")
button.size_hint = (1.0, None)
button.height = "40dp"
button.bind(on_press=self.dismiss)
self.add_widget(button)

Here we’re adding more user interface in Python code and once again we see that it’s bulky compared to the KV Language. We’re still rendering the label, but we’re also adding a button to the bottom of the window. We’re giving it a 40 display pixel height, remembering to set size_hint to None in the y dimension so the layout knows to check the height. We then bind the on_press event of the button to the dismiss method (a callable, remember?) on ModalView. When the button is clicked, the modal disappears. Now it’s much easier to test each of the failure conditions I listed earlier, one after the other.

Technically, this interface still freezes up when we connect, but it’s less invasive since we’re rendering a label instead of broken text areas. The correct fix would probably be to connect in another thread and then schedule interface updates using the Kivy clock, but that’s a bit advanced for this tutorial.

Exiting gracefully

The last problem I want to address today is the fact that we disconnect as soon as we render the Buddy List. That’s not going to be very useful when we get around to actually sending and receiving messages. However, not disconnecting causes the program to hang when we close the window because the xmpp object is sitting there doing it’s job: waiting for incoming jabber messages.

We need to disconnect that object when the window closes. Luckily, Kivy gives us an event on the App class, named stop, that we can hook into to do just that. But let’s arrange our code nicely.

I spend a lot of time rewriting code that I wrote before. Why? To make it more maintainable. I need the code to be readable in the future when I’ve forgotten what it does. Python is designed to be a very readable language, but that doesn’t mean that it’s self organizing. It’s one thing to write readable sentences in English, but quite another thing to have a coherent and cohesive paragraph.

Even though it’s temporary code, the hasattr call in our exception handler (which checks if the xmpp property has been added to the object or not) is a code smell. It would be better if the xmpp property always exists on the object and to check whether or not it is a valid value. So let’s set that property to None by adding an initializer method to the Orkiv class:

(commit)

def __init__(self):
    super(Orkiv, self).__init__()
    self.xmpp = None

Let’s also add a disconnect_xmpp method to the Orkiv class that does the necessary cleanup for us. This method will be called both when the app stops and when the login method fails (but not on successful login). It’s a bit more involved than the dirty call to xmpp.disconnect() that we were making in our temporary code, because we want to be sure to get it right:

(commit)

def disconnect_xmpp(self):
    if self.xmpp and self.xmpp.state.ensure("connected"):
        self.xmpp.abort()
    self.xmpp = None

The conditional checks too things. First, it checks that self.xmpp is an actual object, and not None. If this check is False, python won’t even bother with the second check, which is to see if the ClientXMPP object is connected. I had to actually look through the sleekxmpp source code to figure out how to check if it’s connected using that weird state.ensure syntax. If xmpp IS connected, then we call abort(), which calls the disconnect() method we were calling earlier as well as some other cleanup tasks. Finally, regardless of whether it was connected, we set the xmpp property to None which both frees the memory used by sleekxmpp for garbage collection and puts the app in its known initial state in case we want to try to connect again.

While we’re add it, let’s hook up the stop event handler on the Orkiv. All it needs to do, for now, is call the method we just added:

(commit)

def on_stop(self):
    self.disconnect_xmpp()

You might be wondering why we have two methods, instead of just putting the disconnect_xmpp method body inside of on_stop. There are a couple reasons. One is that we’re going to be calling disconnect_xmpp from a the exception handler in the next example. Of course, we could just call on_stop instead, but that wouldn’t be as readable; the name disconnect_xmpp very clearly describes what the method does. Second, there is every chance that we’ll later have to add additional code to the stop event handler to clean up other things when the app closes. By that point, we’ll likely have forgotten that on_stop is being called from other places, and we may not want the new cleanup code to be called during the connection/login phase. Instant bug! It is often extremely worthwhile to use longer code if it is more readable than a shorter alternative.

Let’s do that last step now: call the disconnect_xmpp method when login fails. We can remove the finally clause, since we no longer want to disconnect if login is successful. And we can remove the hasattr call, since that check is now being done more elegantly inside the disconnect_xmpp method itself:

(commit)

except (XMPPError, InvalidJID):
    self.label.text = "Sorry, couldn't connect, check your credentials"
    button = Button(text="Try Again")
    button.size_hint = (1.0, None)
    button.height = "40dp"
    button.bind(on_press=self.dismiss)
    self.add_widget(button)
    app.disconnect_xmpp()

More on maintaining history

That’s it for coding in this part of the tutorial. I’m a bit concerned that the changes introduced in this tutorial were hard to follow, since we were making sweeping changes all over the file, but I wanted to describe them one at a time. If you’re having trouble following it, you might have better luck looking at the individual git commits. If you select a commit, github will highlight the lines that have been added and removed in each change, making it easier to follow. It also allows you to see the entire file (there’s a “View File” button) if you’re feeling lost. I tried very hard to craft the changes in each commit as well as the commit message so that the history is very easy to follow.

You should try to do this yourself when you are developing. It is unlikely your history will be quite as readable as this repository (my real life repos certainly aren’t!), because it is generally considered unwise to edit your history after you have pushed it to a public repository that other people have seen (think of trying to edit a published book after somebody buys it.) However, before you have pushed your changes, it is perfectly ok to rewrite and reorganize your commits so that they make the maximum amount of sense.

Git provides several tools for such work. One of the easiest to understand is the git commit --amend command. This command is like a regular commit, except that instead of creating a new commit with whatever changes you have prepared with git add, it alters the last committed patch to include those changes. It even allows you to edit the commit message! This is very useful if you make a commit and then realize you forgot to change something in that commit. For example, it’s a terrific way to exclude useless, cluttering commits with messages like “Conform to pep8″, “I forgot to remove a debugging statement”, “Update documentation”, or the most heinous commit message of all: “Blah”.

Another really handy tool that I used extensively while developing this particular tutorial is git add -p <filename>. Because I didn’t actually know exactly how my attempts with the ConnectionModal code were going to work out, I wrote and tested everything before writing the narrative. But then I wanted to commit only specific parts of what I had written in each example, each commit containing a single, coherent collection of changes. git add -p is an extended version of git add (the p is short for --patch) that loops over the changes in the file and allows you to interactively select exactly which hunks you want to go into the next commit. There are quite a few options you can use during each step; press the h to get an overview. Don’t forget to call git commit when you’re done!

Monetary feedback

If you liked the tutorial and would like to see similar work published in the future, please support me. I hope to one day reduce the working hours at my day job to have more time to devote to open source development and technical writing. If you think this article was valuable enough that you would have paid for it, please consider supporting me in one or more of the following ways:

Finally, if you aren’t in the mood or financial position to help fund this work, you can always do your part to share it on your favorite social platforms.

Creating an Application in Kivy: Part 3

This article continues a series on creating a Kivy application. At the end of Part 2, we had a basic form for entering Jabber login details. In this part, we’ll hook up the login button to actually connect to the jabber server and download a Buddy List.

Make sure you’ve completed the previous two parts, or if you want to start from a clean slate, you can clone the end_part_two tag in my git repo for this project. Remember to do your own changes on a separate branch to avoid conflicts later.

git clone https://github.com/buchuki/orkiv.git # or 'git pull' if you've cloned before and want to update
git checkout end_part_two
git checkout -b working_changes
source venv/bin/activate

Table Of Contents

Here are links to other parts of this tutorial.

  1. Part 1: Introduction to Kivy
  2. Part 2: A basic KV Language interface
  3. Part 3: Interacting with widgets and the user
  4. Part 4: Code and Interface Improvements
  5. Part 5: Rendering a Buddy List
  6. Part 6: ListView Interaction
  7. Part 7: Receiving messages and interface fixes
  8. Part 8: Width based layout
  9. Part 9: Deploying your Kivy application

Handling Events

Dictionary.com defines an event as “something that happens, esp. something important”. That’s a perfect description of events in Kivy. Kivy is firing events all the time, but we only have to pay attention to those that we consider important (in the upcoming example, clicking/touching the Login button is important). Every graphical toolkit I have ever used has some concept of events. The difference between Kivy and those other toolkits is that in Kivy, event dispatch and handling is sane and uncomplicated.

If an event is something that happens, then an event handler is something that reacts when an event occurs. Our event handler will eventually log into the server and display the Buddy List, but lets start by printing a quote from a humorous scene in the film Rush Hour. We do this by adding a method to the AccountDetailsForm class in __main__.py:

(commit)

class AccountDetailsForm(AnchorLayout):
    def login(self):
        print("Click the goddamn button")

Remember in Part 1 I mentioned that object oriented programming allowed us to add functionality to existing classes? That’s what we are doing here. The AnchorLayout class has no idea what it might mean to “login” to something, but it makes sense for AccountDetailsForm to do so. So we add a method to the subclass named login. A method is just a function that is aware of which object it is attached to (that’s why it has the parameter self). At this point, we don’t care what object we are attached to, but it will become important soon.

So that method, which we named login, is an event handler. Actually, technically, it’s just a method that happens to handle an event, and we will hook it up by calling that method from the true event handler. Let’s do that next. We just need to add one property to the login Button in our orkiv.kv file:

(commit)

    Button:
        size_hint_y: None
        height: "40dp"
        text: "Login"
        on_press: root.login()

Kivy is really really good about making programmers do the minimal amount of work required. If you add this one line of code and run it, you can click the Login button repeatedly, and each time, the movie quote will show up on the terminal.

The Button widget in Kivy has a press event. The key to signifying an event handler is to add an on_<eventname> property. Now this is where the KV Language gets a little creepy. The code that comes after the event handler property name is standard Python. In fact, you could just use on_press: print("you clicked it") and it would work. Or if you wanted multiple lines of Python, you could put them on the next line, indented, as though the program code was a child widget.

Don’t ever do that. That’s my rule: never have two or more lines of python logic in a KV Language file. When you break this rule, make sure you know for certain that you have a good reason to do it and that you thought that reason all the way through. This will aide you in the future if you ever want to change the layout without trying to sift out the business logic that hasn’t changed. In my mind, the point of KV Language is to define layout and style. You should not mix logic (program code) with the styling. Instead, put the program code on the class in __main__.py and use one line of logic to call that method.

There’s a small amount of magic going on here. The root variable in a KV Language file always refers to the object that is at the left-most indent in our current block. In this case, it’s the <AccountDetailsForm> class, which is the class containing the handy login method. KV Language has two other “magic” variables that you may find useful: app and self. app can be used anywhere in a KV Language file to refer to the object that inherits from Application; so the Orkiv object. Self refers to the current widget. If we called self.x() in the on_press handler, it would refer to the Login Button object itself.

Interacting with widgets

Now, let’s figure out how to get some values out of the textboxes in the form. To this end, we’ll need to refer to objects in the KV Language file from inside the associated class in our __main__.py. This requires a few sets of changes to both files. Let’s start with some minor additions to the elements of our form in orkiv.kv.

(commit)

    Label:
        text: "Server"
    TextInput:
        id: server_input
    Label:
        text: "Username"
    TextInput:
        id: username_input
    Label:
        text: "Password"
    TextInput:
        password: True
        id: password_input

We’ve simply added an identifier to each of our TextInput boxes so that we can refer to them elsewhere in the code. Note that I gave them all consistent names ending in _input. Consistency is very important in programming. Your memory is not infallible, and it would be silly to overtax it by trying to remember that one box is named password and the other is named UserNameTextInput. After years of programming, this statement seems blatantly obvious to me. However, I am frequently frustrated by non-developers who supply (for example) csv files that use spaces and underscores interchangeably or vary the capitalization of identifiers that I need to sanitize before using in program code. Do yourself and everyone else who works with your code a favor and strive for consistency. One really good way to do this in Python code is to strictly follow the Python Style Guidelines even if you disagree with some of the rules. I strongly recommend using a pep-8 highlighter in your editor (I personally use SublimeLinter) to aid you in this pursuit.

Ok, back to the code! The key takeaway is that by giving these widgets an id, we can reference them in other parts of the KV Language file. Specifically, we can set them as the values of custom properties on the AccountDetailsForm class rule like so:

(commit)

<AccountDetailsForm>:
    anchor_y: "top"
    server_box: server_input
    username_box: username_input
    password_box: password_input
    BoxLayout:

We have defined three custom Kivy properties (named server_box, username_box, and password_box) on the AccountDetailsForm class. Each of these properties is assigned a value of the id of one of the text boxes.

It is common to name the properties the same as the ids on the boxes they point to (see my diatribe on consistency above!). However, I chose not to do that here for pedagogical reasons; it’s clear from this example that a property name is a completely different thing from an identifier.

This is no different from setting a property that is meaningful to the parent class such as anchor_y.The difference is that the parent class (AnchorLayout) doesn’t know about them. Neither does the child class, yet, but we’ll now fix that in __main__.py:

(commit)

from kivy.properties import ObjectProperty  # at top of file

class AccountDetailsForm(AnchorLayout):
    server_box = ObjectProperty()
    username_box = ObjectProperty()
    password_box = ObjectProperty()

We added an import statement so we can access Kivy’s ObjectProperty class. Then we specified three instances of this fancy property on the AccountDetailsForm. These instances must have the same names as the properties defined in the KV Language file, since they are referring to the same thing. When the class is constructed, these three properties are defined as having values of None. However, as part of the KV Language parsing process, Kivy applies the styling found in orkiv.kv and overwrites those None values with the three values we specified in the previous example.

So we have widgets that are named by ids in our KV Language file that are being assigned to properties by the same KV Language file that are defined in the __main__.py file. Got that? The upshot of this slightly convoluted pipeline is that we can now access those values inside the login method on our class:

(commit)

    def login(self):
        print(self.server_box.text)
        print(self.username_box.text)
        print(self.password_box.text)

If you run the code now, you should see the contents of the login form boxes displayed on the console when you click the Login button.

Choosing client libraries

Let’s take a break from programming and talk about something that has been overlooked in every programming textbook and tutorial I have ever read: How the hell do you figure out how to do what you need to do?

The short answer, as with every question asked in the last decade, is “Search Google!” (or rather, a search engine that doesn’t spy on you, such as Startpage.com or Duck Duck Go). That always brings out the more salient question, “what do I search for?”.

If you’ve recently started learning to program, you might be under the impression that programming is mostly about connecting loops, conditionals and data structures into some meaningful representation of an algorithm or design pattern. That’s certainly a major part of the job, but often, programming involves reusing existing code and connecting it. Software development is often more like building a lego set where you get to use a variety of prefabricated bricks that do almost exactly what you need, and then using contact cement to glue on some custom-built parts that don’t come with the lego set and can’t be found on store shelves.

Anyway, at this point we have a login form that we can enter details in and do something when the button is clicked. But we aren’t doing what we want to do, which is to display a buddy list for the given XMPP account. How can we do that?

Well, one option might be to read through the Jabber Protocol Specification and implement all the Jabber commands one by one. But that sounds like a lot of work. The absolutely most important attribute in a good programmer is laziness. This means spending hours to automate boring things so you never have to do them again. It also means spending extra time now to write your code in such a way that you or a coworker can reuse it in the future. Finally, it means taking advantage of other people’s work so you don’t have to redo it.

Most common tasks have been collected into what are called “libraries”. Kivy itself is a sort of library, a library for creating kick-ass graphical interfaces. Often when faced with a “how do I do this?” question, the next question should be “Are there any existing client libraries that I can use?” Imagine if you had to manually set the value of each pixel on the screen in order to render a button or textbox, and then process individual keypresses directly to find out what was in a text input box!

Before I started writing this tutorial, I wanted to make sure there was a client library I could use to connect to Jabber. I did a web search and found several options, best summarized by this question on Stack Overflow. Stack overflow is a great place to search for answers; if you can’t find what you are looking for, you can even ask the question yourself!

If a web search yields a nice collection of client libraries that might solve your problem, the next question is, “which one do I use?” The answer is to visit the home pages for each of the libraries and ask yourself questions like these:

  • Is the license compatible with the license I want to use for my application?
  • (If not open source) How much does it cost to license the library?
  • (If open source) Does the source code for the library look well maintained and easy to read?
  • Does the library appear to be actively developed and has there been a recent release?
  • Is there an active user community talking about the library?
  • Does the library appear to have useful (readable, up-to-date, complete) documentation?
  • What avenues of support do I have if I have trouble?
  • (If Python) Does it boast Python 3 support?

After some amount of research, I ended up choosing Sleek XMPP as it seems to have a modern, usable application programmer interface, reasonable source code and documentation, and a permissive license.

At this point, you’ll want to install SleekXMPP and it’s one dependency. Make sure the virtualenv is active and then issue the following command:

pip install sleekxmpp dnspython

Figuring out how to use a client library

The next step is making yourself familiar with the client library so you know what functions and methods to call to create the desired behavior. This depends entirely on the documentation for the library. I personally like to start coding as soon as possible and see what breaks. Then I refer to the documentation and figure out why it broke and evaluate how it needs to change. In the case of SleekXMPP I started exploring the documentation until I could answer the question, “What is the simplest possible command-line application I can use to retrieve a buddy list?”. This is it:

(commit)

import sleekxmpp, sys

xmpp = sleekxmpp.ClientXMPP(sys.argv[1], sys.argv[2])

xmpp.connect()
xmpp.process()
xmpp.send_presence()
xmpp.get_roster()
print(xmpp.client_roster.keys())
xmpp.disconnect()

This script isn’t part of orkiv, it’s just some playing around I did before trying to integrate this collection of method calls into Orkiv. It took me about 20 minutes to come up with these few lines of code, mostly because the SleekXMPP documentation is a little rougher around the edges than I anticipated. I first implemented a couple of the tutorials in the Quickstart and got them working. However, the examples seem to use a verbose inheritance structure that seems quite unnecessary to me. So I tried to extract the guts into the procedural example you see above.

I do my testing inside a running Python shell — just type python and you can start entering python commands right into the interpreter. I personally use IPython as much as possible, because its shell is so much nicer to use than the standard one. At first, my call to get_roster() was returning an error; this was because I hadn’t noticed, in dissecting the inheritance structure, that I had to call connect() first! However, after my trial and error phase were completed, I came up with the above code, which I saved as sleekxmpp_buddylist.py and tested using python orkiv/sleekxmpp_buddylist.py jabberid@jabber.org password. I tested it with a throw-away Google account and my own personal jabber server. Works like a charm!

The script itself first imports a couple modules and creates a ClientXMPP object, passing in the username (in the form “username@server.tld”) and passwords from the command line. Then it calls several methods on this object to do some jabbery stuff. Then I output the value of the roster (“buddy list”), and disconnect.

Printing a buddy list on login button click

We could just copy the code above into the login() method and modify it to use the jabber id and password we got from the form. However, that would be rather short-sighted. We know we’re going to need to keep this ClientXMPP object around longer than a single button click, and indeed, longer than the lifetime of the login form. So instead, lets add a method to the Orkiv application object itself:

(commit)

from sleekxmpp import ClientXMPP  # at the top of the file

class Orkiv(App):
    def connect_to_jabber(self, jabber_id, password):
        self.xmpp = ClientXMPP(jabber_id, password)
        self.xmpp.connect()
        self.xmpp.process()
        self.xmpp.send_presence()
        self.xmpp.get_roster()

That’s a pretty simple method that creates an xmpp attribute on the app class and runs the boilerplate code for connecting to jabber, as we discovered in the script above. Of course, this method won’t actually do anything if we don’t call it from somewhere. The obvious place to do that, of course is when we click the login button. The correct thing to do will be to connect to jabber and then render a buddy list in the window, but we’re running out of space, so let’s just print it to the console:

(commit)

def login(self):
    jabber_id = self.username_box.text + "@" + self.server_box.text
    password = self.password_box.text

    app = Orkiv.get_running_app()
    app.connect_to_jabber(jabber_id, password)
    print(app.xmpp.client_roster.keys())
    app.xmpp.disconnect()

Once again, the method is quite simple. We first grab the jabber id and password from the form box, being careful to concatenate the username and server to generate the jabber id. The next line, where we get the running app may require some explanation. We are calling a function on the Orkiv class itself. Remember, a class describes an object, so we aren’t talking to an instance of that object here, just to the class. When a method is meant to be called on a class instead of an instance of that class, it is called a static method. In this case, the static method happens to return an instance of the class: the currently running app. Normally, there is only ever one running app in a Kivy program. In fact, you’d have to be both foolish and audacious to get more than one.

The other slightly tricky thing about this line is that we have not defined any get_running_app method on the Orkiv class. In fact, we only have one method, connect_to_jabber. But remember that Orkiv inherits functionality from the App, and indeed, App has a get_running_app static method. That’s what we’re calling here.

Once we have access to the active app object, it’s easy to print the roster and disconnect. Obviously, it wouldn’t make sense to disconnect immediately after login in a completed jabber client. However, if you don’t disconnect and test this, the program won’t stop running when you close the window; it leaves the xmpp object hooked up in the background trying to do the kind of stuff that jabber clients do. When I tried it, I had to force kill the process with kill -9.

It is common, when coding, to do temporary things like this to test the program in its current state. We know we’ll remove that line in part 4, but… well, truth be told, part 4 hasn’t been written yet! In part 4, we’ll deal with some annoyances with this form, like the fact that we can’t tab between input fields, that we have no idea what happens if we provide incorrect login details, and that pesky problem of the jabber staying alive after we closed the window.

Monetary feedback

If you liked the tutorial and would like to see similar work published in the future, please support me. I hope to one day reduce my working hours at my day job to have more time to devote to open source development and technical writing. If you think this article was valuable enough that you would have paid for it, please consider supporting me in one or more of the following ways:

I’d particularly like to advertise Gittip, not for my own financial gain, but for everyone. I think a world where people are able to use gittip for their primary source of income is a world worth striving for. Even if you don’t choose to tip me, consider tipping someone, or if you are a producer of knowledge or art, market your own products and services through the generosity system.

Finally, if you aren’t in the mood or financial position to help fund this work, at least share it on your favorite social platforms!

Creating an Application in Kivy: Part 2

This article continues the tutorial we started in Part 1. In the first part, we set up a Kivy project and developed a very basic Kivy application. We also discussed version control to aid in project management. In this part, we’ll be designing an actual user interface for a Jabber client and begin to implement it in the KV language.

Make sure you have completed part 1, or if you want to skip the preliminaries, you can clone the end_part_one tag of the Orkiv git repository and start from there. It’s probably a good idea to name a new branch for your working changes so your master branch doesn’t diverge from my upstream repository. Remember to activate the virtualenv you created in Part 1 (or create one if you’re starting from the git clone.)

git clone https://github.com/buchuki/orkiv.git
git checkout end_part_one
git checkout -b working_changes
source venv/bin/activate

Table Of Contents

Here are links to other parts of the tutorial. I’m sorry for the navigation faux pas; blogs are not the best interface for multi-part articles.

  1. Part 1: Introduction to Kivy
  2. Part 2: Creating a form
  3. Part 3: Interacting with widgets and the user
  4. Part 4: Code and Interface Improvements
  5. Part 5: Rendering a Buddy List
  6. Part 6: ListView Interaction
  7. Part 7: Receiving messages and interface fixes
  8. Part 8: Width based layout
  9. Part 9: Deploying your Kivy application

Interface Design

In general, before developing a user interface, it is a good idea to know what you want it to look like. I see this project having three main views. When the user first opens the application, they’ll see an Account Details screen to provide their jabber server and login credentials. We won’t bother with saving these details since this tutorial series is focused on Kivy interface development, not persistence. Once they have logged in, the other two views are a Buddy List and the individual Chat Window.

I would like to develop the app to show the buddy list and chat windows side by side if the screen is large enough (eg: a laptop screen or large tablet in horizontal orientation), but only one window at a time on small screens. It is very important to evaluate screen size when developing cross platform applications; it is generally not desirable or feasible to render the same view on large monitors and small phones. We’ll look at this feature in later tutorials, but knowing that we want to plan for it now will affect how we implement our design.

All of these windows are pretty simple. In this second part, we will focus on the account details screen. It will be a simple form with labels on the left and fields for entering the various details on the right. The fields covered will include server, username, and password. Below these fields will be a Login button. Normally I’d sketch the interface on a piece of paper, but since this looks like every other Jabber client on the market, I don’t think it’s necessary.

The Account Details Form Widget

In Kivy, virtually every object that gets displayed on the screen is a widget. Just a few examples include:

  • The label we rendered in the first tutorial
  • The text input fields and buttons we’ll render in this tutorial
  • Layout classes that contain other widgets and decide where they should be displayed
  • Complicated tree views such as file pickers
  • Movie and photo renderers
  • Tabbed boxes that display different widgets depending on the selected tab

It is easy to make custom widgets, and to access all widgets, whether custom or otherwise, from KV language files. We’ll be creating a new widget to contain our entire Account Details form. Start by adding a new import and class to __main__.py:

(commit)

from kivy.uix.boxlayout import BoxLayout


class AccountDetailsForm(BoxLayout):
    pass

Running the code with this addition won’t change anything in the output, since the newly created widget hasn’t been added to the root window. However, there are a few things we need to discuss before we change the KV language file to use this widget. You might be asking yourself why we created a new widget instead of adding a BoxLayout widget (whatever that is!) directly to the root of the KV language file orkiv.kv. While it would have been trivial to do this, it would have made putting a new widget (such as the Buddy List) on the root screen more difficult. Further, when it comes time to attach events to the Login button, we can make it a method of this new class, where it makes the most sense.

The BoxLayout is a very simple widget that simply takes the available space and places all the child widgets in it from left to right or top to bottom. By default, each widget gets an equal amount of space, but it’s also possible to make certain widgets have specific sizes or percentages of space or to expand to fill available area.

BoxLayout is one of several kinds of layouts available in Kivy. A layout is simply a container widget that holds other widgets and knows how to position those child widgets in a specific pattern. We’ll be seeing a GridLayout shortly. You can read about other Kivy layouts in the Kivy API Reference.

Let’s edit orkiv.kv to render this new widget as the child form instead of the label we used before. We’ll also add a couple labels to the AccountDetailsForm class so you can see the relationship between root widgets and classes in the KV Language:

(commit)

AccountDetailsForm:

<AccountDetailsForm>:
    Label: 
        text: 'Hello World'
    Label:
        text: 'Another World'

There’s a couple things going on here. The root widget of the Orkiv app is defined as a AccountDetailsForm. This is followed by a colon in case we wanted to add other child widgets to the object, but in this case, it’s just followed by a blank line. Then we define the structure of the child widgets of the AccountDetailsForm class itself. We know it’s a class and not a root widget because the class name is surrounded in angle brackets (< and >). Further, one app can only have one root widget. We just defined that root to be pointing at a single AccountDetailsForm. However, note that a class can be styled once and added in more than one place. Just as our AccountDetailsForm has two labels, it would be possible (though silly, from an interface perspective) to create a container widget that contains two AccountDetailsForms. The point is, an AccountDetailsForm, once its layout has been defined, can be used just like any of the built-in widgets supplied with Kivy.

If you run python orkiv now, it will render the two labels side by side, each taking a full half the window. Note that there are actually three widgets being rendered; first, the AccountDetailsForm (which is a BoxLayout by inheritance) is rendered to fill the whole screen, and then it lays out the two labels as child widgets.

However, that’s not the AccountDetailsForm we were looking for! Let’s create our first nontrivial Kivy Language class. Replace the class in your orkiv.kv with the following:

(commit)

<AccountDetailsForm>:
    orientation: "vertical"
    GridLayout:
        cols: 2
        Label:
            text: "Server"
        TextInput:
        Label:
            text: "Username"
        TextInput:
        Label:
            text: "Password"
        TextInput:
            password: True
    Button:
        text: "Login"

It’s time to discuss just how the Kivy language lays things out. In my mind, it uses a box model similar to HTML, except instead of ugly HTML tags, indentation is used to specify what widgets go inside other widgets. Also, unlike HTML, style information is included in the .kv file instead of an external .css file. Though it’s not a hard and fast rule, style information (called properties in Kivy) typically begins with a lowercase letter, while child widgets start with a capital.

Look at the first level of indentation under the <AccountDetailsForm> declaration. There are three items; orientation, GridLayout, and Button. The former counts as “style information”. Remember that the AccountDetailsForm class extends BoxLayout. One of the attributes on BoxLayout is “orientation”; we are telling BoxLayout here that we want a vertical layout.

This vertical box layout then contains two widgets, a GridLayout and a Button. The GridLayout spaces all it’s children equally. We just have to tell it that there are 2 columns (the cols property) and then start adding our objects, which are displayed from left to right and wrap to the next row in the grid after every two widgets. We add Labels and TextInputs. Each label has a text property that we set using a further level of indent. The TextInput objects don’t require any extra properties except the password.

Later, we’ll have to give these objects some identifiers so we can refer to them in code. For this initial prototyping stage, we can start with the bare minimum. If we render the above example, we end up with a recognizable, but rather ugly form:

example_6

Restricting sizes

Let’s try to make the form a little less ugly:

(commit)

<AccountDetailsForm>:
    orientation: "vertical"
    height: "200dp"
    size_hint_y: None
    GridLayout:
        cols: 2
        row_default_height: "40dp"
        row_force_default: True
        spacing: "10dp"
        padding: "10dp"
        Label:
            text: "Server"
        TextInput:
        Label:
            text: "Username"
        TextInput:
        Label:
            text: "Password"
        TextInput:
            password: True
    Button:
        size_hint_y: None
        height: "40dp"
        text: "Login"

All we’ve done here is add some styling information to make the layout a little more friendly. This can be complicated as we want the app to look good on a variety of devices at a variety of resolutions and screen sizes. The main thing is to ensure all the widgets have a known height. As you might guess, this can be accomplished by adding a height property to each of the widgets. However, doing this alone will not work because BoxLayout likes to think of itself as in charge of deciding what size a widget should be. Without any styling, heights in a vertical BoxLayout are calculated as the number of widgets divided by the available screen space. However, it’s possible to tell BoxLayout to make certain widgets take a higher percentage of available space by giving it a size_hint_y attribute, which should be a float and defaults to 1.0. Unfortunately, for textboxes and buttons, percentages don’t really make a lot of sense, since we have no idea what size the window or screen of a particular advice is going to be, but we do know we want them to be about the same height on each screen.

So in addition to setting the height attribute, we also have to set size_hint_y to None for those widgets to prevent BoxLayout from ignoring the height property and laying things out by percentages instead.

You’ll also note that we are specifying the heights using strings that end in the suffix “dp”. It’s possible to provide integer values here, which would be interpreted as the number of pixels high the button is. However, due to the massive variance in screen resolutions on modern devices, it’s not really feasible to use pixels as a measurement. A login button that is 40 pixels high and looks good on a desktop monitor would look very small, indeed, on a “retina” display tablet.

Therefore, Kivy provides us with the concept of “display pixels”; hence the “dp” in the strings. Display pixels should be about the same size on every device; on a standard desktop monitor they generally map to a single pixel, but on higher density displays, they will be multiplied by a scaling factor. There are other metric properties such as cm or in that you can use, but I generally find it most convenient to think in display pixels.

Note also that instead of supplying heights for each of the Label and TextInput widgets inside the grid layout, we cheated and used the row_default_height attribute so all rows have the same height. For this to work, you also have to set row_force_default to True.

Finally we added spacing and padding properties to the GridLayout to add a 10dp space between child widgets and a “frame” around the whole GridLayout as well. If we run this example, it looks like this:

example_7

There’s one more thing I’d like to do before ending this part of the tutorial. As you can see above, the form is showing up at the bottom of the window, no matter what size the window is. That might look a bit bizarre on a tablet or even phone screen. It would be better if the entire form was anchored to the top of the window.

As an exercise, take a few moments to experiment (remember to use a different git branch!) and see if you can figure out how to move the form to the top by yourself. The next paragraph contains some hints if you get stuck, and the working code is linked after that. (I’m not about to tell you not to cheat, since it really depends what your personal goals are in reading this tutorial.)

There are probably multiple ways to do this, and I’m not even certain my solution is the best one. But I suggest making the AccountDetailsForm into an AnchorLayout and anchor a child BoxLayout to the top of the form. Note that you’ll have to change both files to make this happen.

If you’re still confused, have a look at the full changeset at the changeset on github.

That’s it for part 2 of this tutorial, which focused on laying out widgets in the KV Language. In part 3, we’ll figure out how to log into an XMPP library and render a buddy list. Note that I don’t actually know how to do this, so we’ll have to figure it out together!

Monetary feedback

When I wrote this tutorial, I didn’t expect it to be big or popular enough to publish as a book. However, the series caught O’Reilly’s eye, and I have since written an entire book on Kivy. If you want to support me and learn more about Kivy, you and I both will be delighted if you buy it.

If you like the tutorial and would like to see similar work published in the future, this isn’t the only way to support me. I hope to one day reduce my working hours at my day job to have more time to devote to open source development and technical writing. If you think this article was valuable enough that you would have paid for it, please consider thanking me in one or more of the following ways:

If you aren’t in the mood or financial position to help fund this work, at least share it on your favorite social platforms!

Creating an Application in Kivy: Part 1

This is the first in what I expect to be a series of tutorials on creating user interfaces in Kivy. Kivy is a cross platform user interface framework that allows us to write applications in Python that run on various desktop operating systems, Android, and IOS.

I’ve wanted to write a tutorial on Kivy since hacking on Python 3 support during the dev sprints at Pycon 2013. My goal is to create a useful application that runs on multiple devices and highlights use of the KV Language to design user interfaces. I also want this multi-part series to describe end-to-end how to develop, maintain, and deploy a Kivy application. I intend it to be a model for newcomers to Kivy and even Python to develop their own cross platform or mobile applications in Python. Thus, it doesn’t just include code, but also deployment instructions and information on how to use the git version control system for basic history management.

Therefore, this tutorial series is written at a more basic level than a lot of my technical articles. My intended audience is new programmers who have some basic Python experience; perhaps having read The Python Tutorial and Learn Python The Hard Way, but possibly not the beginner-intermediate topics covered in my book, Python 3 Object Oriented Programming.

Having decided to write a tutorial, I needed to decide what kind of application to develop. This actually took quite a bit of thought. I decided on a Jabber client, as it has a user interface with reasonable complexity, and I am hoping that most of the difficult bits can be abstracted away into the SleekXMPP library. Finally, I had to settle on a name for the app; I chose Orkiv. I do not know why.

Table Of Contents

A blog isn’t the best platform for publishing a multi-part tutorial. I’ll include a Table Of Contents section in each part with references to all the other parts. Hopefully I’ll even keep it up to date!

  1. Part 1: Introduction to Kivy
  2. Part 2: Creating a Form
  3. Part 3: Handling Events
  4. Part 4: Code and Interface Improvements
  5. Part 5: Rendering a Buddy List
  6. Part 6: ListView Interaction
  7. Part 7: Receiving messages and interface fixes
  8. Part 8: Width based layout
  9. Part 9: Deploying your Kivy application

Prerequisites

Start by installing the following pre-requisites using standard operating system tools.

Python is the programming language and interpreter that Kivy programs are written in. Git is a version control system that we will use to track changes to our code. Virtualenv is a tool for creating isolated Python environments. Pip is an installer for installing python packages, in this case into the isolated virtualenv.

Note: Use of git is optional if you are more interested in learning to code than learning to manage a project. You are also welcome to use another version control system of your choice. At the level we will be working, the commands are virtually interchangeable.

Setting up the environment

Run the following commands in a terminal. (Note this tutorial was written using Arch Linux, and will probably work flawlessly on MacOS and other Linux distributions. However, you may need to do some experimenting to make Windows cooperate).

mkdir orkiv
cd orkiv
git init
virtualenv -p python2.7 venv
echo venv >> .gitignore
echo "*.pyc" >> .gitignore
git add .gitignore
git commit -m "Create .gitignore file. Ignores compiled python files and venv."
source venv/bin/activate

We’re creating a directory to hold our project and then initialize a git repository in there. We next create a virtualenv in a folder named venv. This folder will hold the isolated python files so that you can interact with Kivy without adding cruft to your system Python. I highly recommend creating a separate virtualenv for every project you work on.

Next, we set up a .gitignore file that tells git not to track certain files in our repository; in this instance all compiled python files, which end in .pyc, and the virtualenv directory we just created. We commit the changes to this file as our first commit in the git repository.

Finally, we “turn on” the virtualenv by sourcing its activate script. This essentially tells our shell to “use the isolated python for this project instead of system python”. When you are done working on this project, you should enter the command deactivate. When you come back to the project in the future, reenter the source venv/bin/activate command to turn on the isolated environment.

Note: If you maintain a lot of virtualenvs in a lot of different projects, as I do, you may be interested in a small script I wrote to facilitate switching between them.

Kivy Dependencies

Kivy depends on several Python libraries. Unfortunately, it does not have a setuptools-enabled setup.py to automatically install these dependencies into our virtualenv, so we have to do a little work ourselves. This takes a while, but if you copy paste these commands into your terminal, you should get lucky.

pip install cython
pip install pygame

Sadly, on Arch Linux, the last command, for pygame fails. I suspect it works fine on less bleeding edge operating systems, however, if you encounter an error about linux/videodev.h not existing, applying the Arch Linux patch to pygame may get you to the next step.

wget http://www.pygame.org/ftp/pygame-1.9.1release.tar.gz
wget https://projects.archlinux.org/svntogit/packages.git/plain/trunk/pygame-v4l.patch?h=packages/python-pygame -O pygame-v4l.patch
tar xf pygame-1.9.1release.tar.gz
cd pygame-1.9.1release/
patch -Np1 -i ../pygame-v4l.patch
python setup.py install
cd ..
rm pygame* -r

And now, you should finally be ready to install Kivy itself: This will take a while, so grab a smoothie while it runs:

pip install kivy
python -c 'import kivy'

The latter command should output the kivy version (I’m working with 1.7.1). If it exits without failure, then you have successfully installed Kivy!

Now let’s create a basic Kivy app

Create a directory to hold the application code:

mkdir orkiv

This directory will contain your Python and Kivy source files. Our goal is to be able to always create a zipfile from this directory and be able to run it using python orkiv.zip. As long as the required dependencies are installed on the target system (as described above), the program should run. It will therefore be nice and self-contained.

There is a relatively unknown feature of recent versions of Python to support this. If a directory or zipfile contains a __main__.py, that module will be executed if python is called with that directory or zipfile as an argument. First, create a file inside the new orkiv directory named __main__.py. Create a simple “hello world” in this file to test that
it’s working:

(commit)

print("hello world!")

Now from the parent directory, run the command python orkiv. If you want to test it with a zipfile, try this:

cd orkiv
zip ../orkiv.zip *
cd ..
python orkiv.zip

It is possible to code Kivy applications in pure Python, but in my opinion, it is much better to use the amazing KV Language to do layouts. The basic approach is to have a Python file (in our case __main__.py above) that contains the logic for the application, and a KV Language file that contains the layout information. The KV Language is very similar to Python and you can learn it as you go.

Lets start by removing the print statement from our __main__.py and replacing it with the most basic possible Kivy application:

(commit)

from kivy.app import App


class Orkiv(App):
    pass

Orkiv().run()

This simply imports a Kivy App class and creates a subclass of it using Python’s notoriously simple inheritance syntax. Inheritance is a useful feature of Object Oriented Programming that basically means that a class can be defined that has all the functionality of the parent class. In this case, since we didn’t add anything to the subclass, that’s ALL it has. However, the true beauty of inheritance is that we can add new properties and methods (functions attached to objects) to the subclass or even change the functionality that comes with the parent class (App). The best part is, we don’t really have to know what is going on inside the App, and can assume the Kivy devs know what they are doing.

It doesn’t even add anything to the subclass! Then it instantiates an instance of that subclass and calls the run() method on the newly created object.

If you run python orkiv with the new code saved, you’ll see an empty window pop up.

As far as boilerplate goes, that’s pretty damn concise, don’t you think? The amazing thing is that we can start laying out KV Language widgets in a separate file without touching this boilerplate at all! Don’t believe me? Try saving the following as orkiv/orkiv.kv:

(commit)

Label:
    text: "hello world"

Now if you run python orkiv, you should see the “hello world” label centered in the window that pops up. It’s almost like magic, and if you’re like me, you’re probably wondering how that’s even possible.

When you create a subclass of a kivy.app.App, it introspects the name of the new class (we named it Orkiv). Then it looks for a file in the same directory that follows these rules:

  1. Ends with the .kv extension
  2. Starts with the name of the class converted to lowercase and with any
    trailing App stripped.

The Kivy documentation would have named the class OrkivApp and still used the orkiv.kv filename. Personally, I don’t see the redundant need to add App to the class name, since the inheritance structure clearly indicates that Orkiv is a App.

We’ll be working with the Kivy Language a lot as we proceed through each part of this tutorial. You’ll soon see that it’s possible to do more, a lot more, than add a label to a window!

A note on version control

At this point, you’ve created a logical related set of changes that are in a working state. I want to encourage you to experiment with these files, maybe change the contents of the label, try a different application and KV Language filename, or see if you can figure out how to group two labels into a single layout. But before doing that, you should record this known state that your repository is currently in so it’s easy to get back to. That way, you can be free to explore without fear of getting completely lost; you’ll always have a path straight back to your current state. You can do that from the command line using git:

git add orkiv/
git commit -m "A basic Kivy boiler plate"

You just made a commit on the master branch in git. First you listed the changes you wanted to include in the commit (the entirety of every file in the new orkiv directory), then you told git to record the current state of those files forever. It is generally recommended that you only save consistent, known-to-be-working state on the master branch. For the purposes of this tutorial, I suggest that you only save the code you copied from the tutorial to the master branch, and do your other development on other branches.

Are you confused by what a branch is, exactly? Think of it like walking down a forest path in a national park. You are following signs for a marked trail; that’s this tutorial. As you walk, you see things that you want to remember, so you take a photo. That’s like making a commit on the master branch. However, you also see side paths that you would like to explore on your own. You can go down that path as far as you want, or even take other random paths without fear of getting lost. You can even take photos on those paths, knowing they won’t get mixed in with the photos from the main trail. Then when you want to return to the point where you left the main trail, you can magically teleport back to it (or indeed, to any of the other branches you walked down in your exploration).

You probably won’t be doing it for this tutorial, but the most import aspect of version control is that if you are in unmarked forest rather than a national park, you can walk down all the paths and decide which one you’re going to choose as the main path. You can even merge paths back into each other so that the photos (code commits) taken on each of them end up in the same final presentation.

Enough digressing! For your purposes, the first thing you should do is create a new branch in git:

git checkout -b my_exploration

You are now on a new branch named my_exploration (you can call each branch whatever you want, of course) that is exactly the same as the master branch as you last saw it. But you can make changes on that branch to your heart’s content; you can add and commit them as above if you want to remember them for later. When you’re ready to come back to the tutorial, you can use this command to return to the current state of the master branch:

git checkout master

From there, you could continue with the next part of the tutorial, or you could create a new branch and explore in a different direction.

Browsing the examples

I am maintaining my own version of the code developed in this tutorial at https://github.com/buchuki/orkiv/. However, it’s not likely to be the same as your repository, since I’m not making commits at the same time that I’m suggesting you make commits. Instead, my master branch contains a separate commit for each example in the tutorial. I also create git tags for each part of the tutorial so it’s fairly easy to see from commit history what was covered in each part. If you browse the Commit History you can see each example and how it evolved from top to bottom. You can view the list of tags here.

Monetary feedback

When I wrote this tutorial, I didn’t expect it to be big or popular enough to publish as a book. However, the series caught O’Reilly’s eye, and I have since written an entire book on Kivy. If you want to support me and learn more about Kivy, you and I both will be delighted if you buy it.

If you like the tutorial and would like to see similar work published in the future, this isn’t the only way to support me. I hope to one day reduce my working hours at my day job to have more time to devote to open source development and technical writing. If you think this article was valuable enough that you would have paid for it, please consider thanking me in one or more of the following ways:

If you aren’t in the mood or financial position to help fund this work, at least share it on your favorite social platforms!