Starting to Use Kivy : Developing "Letter of Heroes", An Android Alphabet Teaching Aid for Kids Part 2 of 2

 

"Letter of Heroes" in a Samsung Galaxy Tab 2 - Showing Captain America when you pressed the letter "K" (because we read it as Kapten Amerika in Indonesia tongue)

Previously we already have a nice installation of Kivy whether it sit in our development machine or within a pre-configured Linux Ubuntu Quantal VirtualBox machine pre-built with Python for Android environment, to ease the process of packaging Kivy into Android APK. After playing around with Kivy examples code, I found that Python programmers would not have any difficulty in doing mobile application Android development. "Why?", well, because, it simply Python! It just get runs on Android using Python for Android. The core of the problem may lies in the Android integration part of Kivy : e.g. accessing camera, using GPS, Accelerometer, etc. But thanks to Pyjnius, that issues seems to simply fade away. Sure more work must be done before a unifying API for both iOS/Android can be achieved, but from what I see from Kivy progress in the recent years, it looks very good! As for iOS implementation itself, Kivy have Pyobjus that making it easier to access iOS API. Things are pretty interesting there... Smile

In this article we are going to develop our own Python application using Kivy and deploy it in a Samsung Galaxy Tab 2 device.  Lets have a look!

Application Requirements 

"Letter of Heroes" application requirement is very simple, here goes : "Display all the letter from A to Z, in which upon pressing it, lets display a still image of the superhero having name begins with that letter and also play a pre-recorded sound for that superhero". The fun part is, let our kids Google their own superhero and record their own voice loudly! Here is a quick UI sketches for this particular application :

GUI sketches

Letter of Heroes GUI Sketches

Starting Kivy Application Development

We develop Kivy application using the usual Python language we already familiar (and love) with. By convention, our main application code must reside in a single main.py file in an application root directory. As for the GUI design itself, Kivy has its own language, called Kv language. Work is in progress in Kivy community to build a Kivy designer. As much as we eager to try the stable product of Kivy Designer, for now, lets see how we can design our application GUI using the plain Python or Kv language.

Using Python Code to Design Application GUI

Lets create a new directory named letterofheroes and create a single main.py file in it with the following contents:

1
2
3
4
5
6
7
8
9
10
11
12
from kivy.app import App
from kivy.uix.widget import Widget
 
class Controller(Widget):
    pass
 
class LetterOfHeroesApp(App):
    def build(self):
        return Controller()
 
if __name__ == '__main__':
    LetterOfHeroesApp().run()

 

The above code is the simplest Kivy application you can build. It will display nothing but a blank screen. Try to run it!

If you use the provided Linux VM, just issue the command : python main.py. It already equipped with Cython and other packages needed for it to successfully run. While in Windows, if you happened to use the Kivy distribution downloaded from Kivy download page, you have to use kivy.bat batch file to run it using this command : kivy.bat main.py.

In the code above, our main application is being started in its __main__ block (a nice reference is here). This will eventually call LetterOfHeroesApp.build() method, which must return an object that provide canvas property, to let Kivy draw things to the screen. In this simplest case, I derived Controller from  Widget class, which is Kivy building block for GUI interfaces, that already provided a Canvas object. Having done this, the above application is ready to be run in .. Android! (no kidding!).

A blank screen is not enough. Lets add another complexity to the above code by displaying a simple text message in the main screen as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
 
class Controller(Widget):
    def __init__(self):
        Widget.__init__(self)
        label = Label(text="Howdy!")
        self.add_widget(label)
 
class LetterOfHeroesApp(App):
    def build(self):
        return Controller()
 
if __name__ == '__main__':
    LetterOfHeroesApp().run()

In the Controller class constructor, I add a Kivy Label widget to the root of our GUI Controller class. An important note though, don't forget to initialize your super class. If you don't do this, you'll have segmentation problem. Try to run it,  and you will have screenshot resembling the picture below:

Probably still not the simplest Kivy application :)

Probably still not the simplest Kivy application :)

 

To finalize this section, let's add a complete event driven feature to the above application, by adding a button that will display a warm message in a Kivy popup window. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.uix.label import Label
 
class Controller(Widget):
    def __init__(self):
        Widget.__init__(self)
        btnHello = Button()
        btnHello.text = "Greet"
        btnHello.bind(on_press = self.btnHello_pressed)
        self.add_widget(btnHello)
 
    def btnHello_pressed(self, event):
        popup = Popup(title = "Letter of Heroes", 
                content = Label(text = "Howdy Pythonistas!"), 
                size = (200,200), 
                size_hint=(None, None),
                auto_dismiss=True)
        popup.open()
 
class LetterOfHeroesApp(App):
    def build(self):
        return Controller()
 
if __name__ == '__main__':
    LetterOfHeroesApp().run()

The significant change in the above code is how we use the bind() method to attach a Button event, on_press, to a Python method, btnHello_pressed. Cool isn't it? Cool

Upon running it, you will find an application screenshot resemble this picture below:

A complete multi touch event driven application

A complete multi touch event driven application

But for those who are used to develop GUI applications, the above example may seems awkward : "Squeezing GUI design into application code? Even HTML has its own CSS!". That's right. In later section of this tutorial we are going to see how to better separate our application GUI code.

Developing Letter of Heroes

Let start the development of this application by thinking about the layout first. We need to let Kivy arrange our button alphabets neatly from left to right and top to bottom, with enough spacing between buttons. Having a quick look at Kivy layouts, I am sure StackLayout will serve our need. A simple StackLayout that arrange 26 buttons will completely solved this application GUI design, isnt' it? For each button we must also need for it to bind to a Python code in our Python controller class that will play a recorded sound and popup still image of superhero in questioned. Let's divide this development into two parts : its Kv file and its Py file.

Separating GUI from Code using Kv File

Although previous code examples are working just fine, you shouldn't develop your application using that method. By simply coding the application GUI within your application code will create havoc: you will ended up with a code having application logic (controller) and user interface intertwined each other. Thanks to Kivy Kv language, that problem is resolved : application developer can move all of its GUI design code into another file (having *.kv extension). And as I said previously, currently Kivy designer tool that lets us produce this Kv file is undergo an active development. Kivy development will be perfect once it's done!

As for now, lets build our Letter of Heroes user interface using a single file named controller.kv. You can recognize that, the file name is derived from its Python user interface controller class. So, if you use Game as its user interface controller class (saved in main.py), the corresponding Kv file must be named game.kv (I experience that you must use lower case for the file name though)

Using our GUI sketches, below are the snippet of our application user interface in Kv language:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<Controller>:    
  StackLayout:
    orientation: 'lr-tb'
    padding: 10
    spacing: 5
    Button:
      text: "A"
      size_hint: root.xhint, root.yhint
      on_press: root.do_pressletter('a')
    Button:
      text: "B"
      size_hint: root.xhint, root.yhint
      on_press: root.do_pressletter('b')
    Button:
      text: "C"
      size_hint: root.xhint, root.yhint
      on_press: root.do_pressletter('c')
...
...
...
    Button:
      text: "Z"
      size_hint: root.xhint, root.yhint
      on_press: root.do_pressletter('z')

I am sure the above Kv file syntax is quite self explanatory : it clearly displayed things in a hierarchical fashion using intended block for ease of reading as in Python source code. The root element name is, not surprisingly Controller, which is the name of its user interface controller class. It start with a StackLayout element, where first we define all of its properties that are in our concern. And finally we add the rest of the 26 alphabet buttons in it. Each button having a size_hint (percentage size) property coming from Controller class, in which we use root keyword (another pre-defined keyword in a Kv file is self, app and arg). We also define its event on_press to be bind to method  do_pressletter  in Controller class.

Pretty easy, right? Here is the screenshot of this user interface, running in Windows environment.

Letter of Heroes user interface using Stacklayout container

Letter of Heroes user interface using Stacklayout container

 

Completing Application User Interface Controller Class

Without further ado, below is the complete Letter of Heroes user interface controller class saved in main.py .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.stacklayout import StackLayout
from kivy.properties import ObjectProperty, StringProperty, NumericProperty
from kivy.uix.popup import Popup
from kivy.uix.image import Image
from kivy.core.window import Window
from kivy.core.audio import SoundLoader
import os
 
class Controller(StackLayout):
    xhint = NumericProperty(.15)
    yhint = NumericProperty(.15)
    letters = {}
    letters['a'] = 'Avengers'
    letters['b'] = 'Batman'
    letters['c'] = 'Cyclops'
    letters['d'] = 'Dare Devil'
    letters['e'] = 'Elastic Man'
    letters['f'] = 'Flash'
    letters['g'] = 'Green Lantern'
    letters['h'] = 'Hulk'
    letters['i'] = 'Iron Man'
    letters['j'] = 'Justice League'
    letters['k'] = 'Kapten Amerika'
    letters['l'] = 'Lucius Fox'
 
    letters['m'] = 'Martian Manhunter'
    letters['n'] = 'Nightwing'
    letters['o'] = 'Owlman'
    letters['p'] = 'Phantom'
    letters['q'] = 'Quick Silver'
    letters['r'] = 'Robin'
    letters['s'] = 'Superman'
    letters['t'] = 'Thor'
    letters['u'] = 'Ultraman'
    letters['v'] = 'Voltus 5'
    letters['w'] = 'Wolverine'
    letters['x'] = 'X-Men'
    letters['y'] = 'Yoda'
    letters['z'] = 'Zodd'
 
    def do_pressletter(self, letter):
        popup = Popup(title= self.letters[letter],
                    content=Image(source="img/" + letter + ".png"),
                    size_hint=(None, None), size=(Window.width - 20, Window.height - 50),
                    auto_dismiss=True)
        filename = 'snd/' + letter + '.ogg'
        if not os.path.exists(filename):
            filename = 'snd/default.ogg'
        sound = SoundLoader.load(filename)
        sound.play()
        popup.open()
 
class LetterOfHeroesApp(App):
    def build(self):
        return Controller()
 
if __name__ == '__main__':
    LetterOfHeroesApp().run()

 

We simply use a Python dict to associate a letter to its superheroes. There are one new thing there : a NumericProperty object, which is a Kivy property object. It's a special purpose object provided by Kivy to ease us in handling object property. We need these two properties (xhint and yhint) to set all those 26 buttons size_hint property.

There is an important note about playing the sound though. I found that Kivy having trouble when playing certain WAV/MP3 file. I think its due to its audio coder being used in those files. My guess is, using OGG Vorbis audio format may solved that problem. There are way lots of Sound Recorder application available in Google Play Store, in this occasion I choose Smart Voice Recorder that seems working just fine. It produced a WAV file. And to convert them to OGG file format, I simply have a look on Ubuntu available packages using the command apt-cache search wav to ogg converter. And finally I install dir2ogg, a very understanding tool that convert all WAV files in a directory into OGG format!

Dam*! I love Open Source! Laughing

Conclusion

Up until now, this application run just well in my Samsung Galaxy Tab 2. But I cannot guaranteed it to run in your Android device. Have been working in Gameloft, Jogjakarta, Indonesia for several months, made me realize that, targeting all handheld devices is entirely a different beast than developing the original application itself.

One issue though, that is, when playing this appliction in my Windows machine, the sound got played in high pitched sound (it sounded like Alvin and The Chipmunks!). I haven't tried solving that issue, as my target is running it in an Android device. Maybe later.

For those interested, you can directly download this application APK file here. Or, grab its Github source here.

Stay tuned for my next article! I may talk more about Kivy or ... continuing the previous PyCocos2d-x project!





Leave comments

 authimage
  • For those who are not spoken Bahasa Indonesia, here is the translation :

    Q : "What about it speed?"
    A : "No problem. But, anyway, this is Python. Even when doing desktop development, initially we always though : isn't it a compiled language better than its interpreted one? The same is the case with Kivy. Everything is just fine. Although I would love to have speed chart comparison published from Kivy community itself.

    We also must counted for its ease of development, because what we use is a pure Python. Imagine if we have to develop in Java. Personally I don't want to revert to Java for any Android development. For example, if it's about game development, I would love to choose either Cocos2d-x or UDK. Or Unity..
    (Woops, we have plenty of choices there!)

    If we want to revert to Android API we can use Pyjnius for that
    Try to download the APK and test it in your Android device!"

    • eko
  • Ga masalah kok ini :)
    Tapi memang maklum sih : Python gitu loh. Kalau kita develop Python di desktop aja, pasti mikir, "lebih kenceng kalau aplikasi yang terkompile jadi exe". Ya ga?

    nah, sama deh kasus Kivy ini.
    Oke2 aja tuh!
    meski, aku jg mau tanya ada ga chart kecepatan yang bs dipulikasi dari komunitas kivy itu sendiri.

    Juga harus dipertimbangkan ease of development-nya, karena kita bener2 pakai pure Python. Bayangin kalau harus belajar Java dari nol. Ane aja rada wegah koding kembali ke Java :D
    Paling kalau mau develop games yang rada native, mau pakai Cocos2d-x aja
    Atau UDK sekalian
    Atau Unity..
    ( gile, banyak bener yaks pilhannya. wkwk )

    Kalau mau revert ke Android API jg bs pakai Pyjnius itu

    Coba aja download APK-nya dan test di android mu

    • eko
  • bagaimana kecepatannya om ?

    • fird0s

Copyright(c) 2014 - PythonBlogs.com
By using this website, you signify your acceptance of Terms and Conditions and Privacy Policy
All rights reserved