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!

17 Comments

  1. [...] Creating an Application In Kivy: Part 1 Creating an Application in Kivy: Part 3 [...]

  2. Bryan Lott says:

    Just one “bug”:

    When you add the library with a from x import y, you don’t need to include x when you call y. I.e., the following code should be changed:

    #from
    from sleekxmpp import ClientXMPP # at the top of the file

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

    #to
    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()

    • Dusty Phillips says:

      Good catch, I’ve fixed it. It must have been a copy paste error from my example repository, since everything is running there.

      Thanks for the proofreading! I’ve had less time to devote to editing than I normally do on articles, since I’m trying to stay on a schedule with this series.

  3. domzy says:

    I might be wrong about this, but at this part, in the 4th line, shouldn’t it be Orkiv().get_running_app() instead of just Orkiv.get_running_app() ?

    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()

  4. [...] 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 [...]

  5. [...] 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. [...]

  6. Antonio says:

    Hey man, is there a new version of you book coming? I’m looking forward about it!

    • Dusty Phillips says:

      The publisher of Python 3 OOP hasn’t contacted me to make any revisions. To be honest, the book is quite timeless with the exception of the library support chapter at the end, which is, of course, out of date as soon as it’s written. It would be nice to add something on Django and, of course, Kivy, but it will probably be a while before other chapters require update.

  7. [...] Dusty's Diverse Domain » Blog Archive » Creating an Application in Kivy: Part 3 says: July 31, 2013 at 7:50 pm [...]