Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Kivy Blueprints
Kivy Blueprints

Kivy Blueprints: Build your very own app-store-ready, multi-touch games and applications with Kivy!

eBook
NZ$14.99 NZ$57.99
Paperback
NZ$71.99
Subscription
Free Trial

What do you get with a Packt Subscription?

Free for first 7 days. $19.99 p/m after that. Cancel any time!
Product feature icon Unlimited ad-free access to the largest independent learning library in tech. Access this title and thousands more!
Product feature icon 50+ new titles added per month, including many first-to-market concepts and exclusive early access to books as they are being written.
Product feature icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Product feature icon Thousands of reference materials covering every tech concept you need to stay up to date.
Subscribe now
View plans & pricing
Table of content icon View table of contents Preview book icon Preview Book

Kivy Blueprints

Chapter 1. Building a Clock App

This book will walk you through the creation of nine little Kivy programs, each resembling a real-world use case for the Kivy framework. On many occasions, the framework will be utilized together with other Python modules fitting for the task at hand. We will see that Kivy provides a great deal of flexibility, allowing us to solve vastly different problems in a clean, concise manner.

Let's start small. In this chapter, we will build a simple Clock app, similar in concept to the built-in application found in both iOS and Android. In the first part of the chapter, we will create a non-interactive digital clock display and style it, giving our program an Android-ish flat look. We will also briefly discuss the event-driven program flow and a Kivy main loop, introducing timers used to perform recurring tasks, such as updating the screen every frame.

In the second part of this chapter, we will add a stopwatch display and controls, creating a fluid layout suitable for any screen size and orientation. A stopwatch, naturally, needs user interaction, which we are going to implement last.

The important topics introduced in this chapter are as follows:

  • The basics of the Kivy language, a built-in domain-specific language (DSL) used to lay out widgets
  • Styling (and eventually subclassing) built-in Kivy components
  • Loading custom fonts and formatting text
  • Scheduling and listening to events

Our finished program, depicted in the following screenshot, will only be about 60 lines long, split equally between a Python source code and a Kivy language (.kv) interface definition file.

Building a Clock App

The final look of the Clock app we're going to build.

The starting point

Our "Hello, Kivy" example from the preface is a suitable starting point for this app. We just need to add a layout container, BoxLayout, so that we can fit more than one widget on the screen later.

This is the full source code at this point:

# File: main.py
from kivy.app import App

class ClockApp(App):
    pass

if __name__ == '__main__':
    ClockApp().run()

# File: clock.kv
BoxLayout:
    orientation: 'vertical'

    Label:
        text: '00:00:00'

Right now, it looks and behaves exactly like the previously seen "Hello, world" app. A BoxLayout container allows two or more child widgets to coexist side by side, stacking either vertically or horizontally. Given just one nested widget, as in the preceding code, BoxLayout fills up all the available screen space with it and thus becomes practically unnoticeable (it's as if Label was a root widget instead, taking over the application window). We will review layouts in more detail later on.

Note

Note that while we may call the main.py file anything we want, the clock.kv file is autoloaded by Kivy, and therefore, has to be named after the application class. For example, if our app class is called FooBarApp, a corresponding .kv file should be named foobar.kv (the class name converted to lowercase and without the -app suffix). Closely following this naming convention allows us to avoid loading Kivy language files manually, which is unequivocally a good thing—less lines of code leading to the same result.

Modern UI

At the time of writing this, the flat design paradigm is trending in the interface design field, systematically taking over every platform, be it Web, mobile, or desktop. Prominent examples of this paradigm shift in the wild are iOS 7 and later and Windows 8 and later. Internet companies followed suit with the "Material design principles" presented at Google I/O 2014 conference, along with many other HTML5 frameworks, including the well-established ones, for example, Bootstrap.

Conveniently, the flat design emphasizes content over presentation, omitting photo-realistic shadows and detailed textures in favor of plain colors and simple geometry. It is by all means simpler to create programmatically than the "old school" skeuomorphic design that tends to be visually rich and artistic.

Note

Skeuomorphism is a common approach to user interface design. It is characterized by applications visually imitating their real-world counterparts, for example, a Calculator app with the same button layout and look and feel as a cheap physical calculator. This may or may not help user experience (depending on who you ask).

Giving up visual details in favor of a simpler, more streamlined interface seems to be the direction everyone is going in today. On the other hand, it's naturally challenging to build a distinctive, memorable interface just from colored rectangles and such. This is why the flat design is typically synonymous with good typography; depending on the application, text is almost always a significant part of the UI, so we want it to look great.

Design inspiration

Imitation is the sincerest form of flattery, and we will imitate the clock design from Android 4.1 Jelly Bean. The distinctive feature of this design is the font weight contrast. Until it was changed in version 4.4 KitKat, the default clock used to look like this:

Design inspiration

Clock in Jelly Bean flavor of Android, as seen on the lock screen.

The font used is Roboto, Google's Android font that superseded the Droid font family in Android 4.0 Ice Cream Sandwich.

Roboto is free for commercial use and available under the permissive Apache License. It can be downloaded from Google Fonts or from the excellent Font Squirrel library at http://www.fontsquirrel.com/fonts/roboto.

Loading custom fonts

When it comes to the typography, Kivy defaults to Droid Sans—Google's earlier font. It's easy to replace Droid with a custom font, as Kivy allows us to specify the font_name property for textual widgets (in this case, Label).

In the simplest case when we have just one font variant, it is possible to assign a .ttf filename directly in the definition of a widget:

Label:
    font_name: 'Lobster.ttf'

For the aforementioned design, however, we want different font weights, so this approach won't cut it. The reason being, every variation of a font (for example, bold or italic) commonly lives in a separate file, and we can only assign one filename to the font_name property.

Our use case, involving more than one .ttf file, is better covered by a LabelBase.register static method. It accepts the following arguments (all optional), exemplified by the Roboto font family:

# In Python code
LabelBase.register(name="Roboto",
    fn_regular="Roboto-Regular.ttf",
    fn_bold="Roboto-Bold.ttf",
    fn_italic="Roboto-Italic.ttf",
    fn_bolditalic="Roboto-BoldItalic.ttf")

After this invocation, it becomes possible to set the font_name property of a widget to the name of the previously registered font family, Roboto in this case.

This approach has two limitations to be aware of:

  • Kivy only accepts TrueType .ttf font files. If the fonts are packaged as OpenType .otf or a web font format such as .woff, you may need to convert them first. This can be easily done using the FontForge editor, which can be found at http://fontforge.org/.
  • There is a maximum of four possible styles per font: normal, italic, bold, and bold italic. It's fine for older font families, such as Droid Sans, but many modern fonts include anywhere from 4 to over 20 styles with varying font weight and other features. Roboto, which we're going to use shortly, is available in at least 12 styles.
Loading custom fonts

The six font weights of Roboto font

The second point forces us to choose which font styles we will use in our application as we can't just throw in all 12, which is a bad idea anyway as it would lead to a hefty increase in file size, up to 1.7 megabytes in the case of Roboto family.

For this particular app, we only need two styles: a lighter one (Roboto-Thin.ttf) and a heavier one (Roboto-Medium.ttf), which we assign to fn_regular and fn_bold respectively:

from kivy.core.text import LabelBase

LabelBase.register(name='Roboto',
                   fn_regular='Roboto-Thin.ttf',
                   fn_bold='Roboto-Medium.ttf')

This code should be placed right after the __name__ == '__main__' line in main.py, as it needs to run before the interface is created from the Kivy language definition. By the time the app class is instantiated, it might already be too late to perform basic initialization like this. This is why we have to do it in advance.

Now that we have a custom font in place, all that's left is to assign it to our Label widget. This can be done with the help of the following code:

# In clock.kv
Label:
    text: '00:00:00'
    font_name: 'Roboto'
    font_size: 60

Formatting text

The most popular and universally used markup language out there is undoubtedly HTML. Kivy, on the other hand, implements a variant of BBCode, a markup language once used to format posts on many message boards. Visible distinction from HTML is that BBCode uses square brackets as tag delimiters.

The following tags are available in Kivy:

BBCode tag

Effect on text

[b]...[/b]

Bold

[i]...[/i]

Italic

[font=Lobster]...[/font]

Change font

[color=#FF0000]...[/color]

Set color with CSS-like syntax

[sub]...[/sub]

Subscript (text below the line)

[sup]...[/sup]

Superscript (text above the line)

[ref=name]...[/ref]

Clickable zone, <a href="…"> in HTML

[anchor=name]

Named location, <a name="…"> in HTML

Tip

This is by no means an exhaustive reference because Kivy is under active development and has probably undergone a number of releases since this text was written, adding new features and refining the existing functionality. Please refer to the Kivy documentation found on the official website (http://kivy.org) for an up-to-date reference manual.

Let's return to our project. To achieve the desired formatting (hours in bold and the rest of the text in fn_regular thin font), we can use the following code:

Label:
    text: '[b]00[/b]:00:00'
    markup: True

Kivy's BBCode flavor works only if we also set the markup property of a widget to True, as shown in the preceding code. Otherwise, you will literally see the string [b]…[/b] displayed on the screen, and that's clearly not desired.

Note that if we wanted to make the whole text bold, there is no need to enclose everything in [b]…[/b] tags; we could just set the bold property of the widget to True. The same applies to italic, color, font name, and size—pretty much everything can be configured globally to affect the whole widget without touching markup.

Changing the background color

In this section, we will adjust the window background color. Window background (the "clear color" of OpenGL renderer) is a property of a global Window object. In order to change it, we add this code right after the __name__ == '__main__' line in main.py:

from kivy.core.window import Window
from kivy.utils import get_color_from_hex

Window.clearcolor = get_color_from_hex('#101216')

The get_color_from_hex function is not strictly required, but it's nice as it allows us to use CSS-style (#RRGGBB) colors instead of (R, G, B) tuples throughout our code. And using CSS colors is preferable for at least the following two reasons:

  • Less cognitive overhead when reading: The #FF0080 value is immediately recognized as a color when you're familiar with this notation, while (255, 0, 128) is just a bunch of numbers that may be used differently depending on the context. The floating-point variant of #FF0080, (1.0, 0.0, 0.50196) is even worse.
  • Simple and unambiguous searching: A tuple can be arbitrarily formatted, while a CSS-like color notation is uniform, albeit case-insensitive. Performing a case-insensitive search in most text editors is very simple, as opposed to locating all instances of a given tuple inside a lengthy Python listing. The latter task can prove challenging and involve regular expressions, among other things, because the formatting of tuples doesn't have to be consistent.

Tip

More information about the #RRGGBB color format can be found on Mozilla Developer Network at https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_started/Color.

We will talk more about design-related features of Kivy later on. Meanwhile, let's make our application actually show the time.

Making the clock tick

UI frameworks are mostly event-driven, and Kivy is no exception. The distinction from the "usual" procedural code is simple—the event-driven code needs to return to the main loop often; otherwise, it will be unable to process events from a user (such as pointer movement, clicks, or window resize), and the interface will "freeze". If you're a longtime Microsoft Windows user, you are probably familiar with programs that are unresponsive and freeze very often. It is crucial to never let this happen in our apps.

Practically, this means that we can't just code an infinite loop like this in our program:

# Don't do this
while True:
    update_time()  # some function that displays time
    sleep(1)

Technically, it might work, but the application's UI will stay in the "not responding" state until the application gets killed (forcefully stopped) by the user or an operating system. Instead of taking this faulty approach, we need to keep in mind that there is a main loop running inside Kivy, and we need to take advantage of it by utilizing events and timers.

Event-driven architecture also means that in many places, we will listen to events to respond to various conditions, be it user input, network events, or timeouts.

One of the common events that many programs listen to is App.on_start. A method with this name, if defined on the application class, will be called as soon as the app is fully initialized. Another good example of an event that we will find in many programs is on_press, which fires when the user clicks, taps, or otherwise interacts with a button.

Speaking of time and timers, we can easily schedule our code to run in the future using a built-in Clock class. It exposes the following static methods:

  • Clock.schedule_once: Runs a function once after a timeout
  • Clock.schedule_interval: Runs a function periodically

Note

Anyone with a JavaScript background will easily recognize these two functions. They are exactly like window.setTimeout and window.setInterval in JS. Indeed, the Kivy programming model is very similar to JavaScript even if the API looks completely different.

It's important to understand that all timed events that originate from Clock run as a part of Kivy's main event loop. This approach is not synonymous to threading, and scheduling a blocking function like this may prevent other events from being invoked in a timely manner, or at all.

Updating the time on the screen

To access the Label widget that holds time, we will give it a unique identifier (id). Later, we can easily look up widgets based on their id property—again, a concept which is very similar to web development.

Modify clock.kv by adding the following:

Label:
    id: time

That's it! Now we can access this Label widget from our code directly using the root.ids.time notation (root in our case is BoxLayout).

Updates to the ClockApp class include the addition of a method to display time, update_time, which looks like this:

def update_time(self, nap):
    self.root.ids.time.text = strftime('[b]%H[/b]:%M:%S')

Now let's schedule the update function to run once per second after the program starts:

def on_start(self):
    Clock.schedule_interval(self.update_time, 1)

If we run the application right now, we'll see that the time displayed is being updated every second. To paraphrase Neil Armstrong, that is one small step for mankind, but a sizable leap for a Kivy beginner.

It's worth noting how the argument to strftime combines Kivy's BBCode-like tags described earlier with the function-specific C-style format directives. For the unfamiliar, here's a quick and incomplete reference on strftime formatting essentials:

Format string (case-sensitive)

Resulting output

%S

Second as two digits, typically 00 to 59

%M

Minute as two digits, 00 to 59

%H

Hour as per 24-hour clock, 00 to 23

%I

Hour as per 12-hour clock, 01 to 12

%d

Day of the month, 01 to 31

%m

Month (numeric), 01 to 12

%B

Month (string), for example, "October"

%Y

Year as four digits, such as 2016

Tip

For the most complete and up-to-date documentation on displaying time, please refer to the official reference manual—in this case, Python standard library reference, located at https://docs.python.org/.

Binding widgets using properties

Instead of hardcoding an ID for each widget that we need to access from Python code, we can also create a property and assign it in a Kivy language file. The motivation for doing so is mostly the DRY principle and cleaner naming, at a cost of a few more lines of code.

Such a property can be defined as follows:

# In main.py
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout

class ClockLayout(BoxLayout):
    time_prop = ObjectProperty(None)

In this code fragment, we make a new root widget class for our application based on BoxLayout. It has a custom property, time_prop, which is going to reference Label we need to address from Python code.

Additionally, in the Kivy language file, clock.kv, we have to bind this property to a corresponding id. Custom properties look and behave no different from the default ones and use exactly the same syntax:

ClockLayout:
    time_prop: time

    Label:
        id: time

This code makes the Label widget accessible from the Python code without knowing the widget's ID, using the newly defined property, root.time_prop.text = "demo".

The described approach is more portable than the previously shown one and it eliminates the need to keep widget identifiers from the Kivy language file in sync with the Python code, for example, when refactoring. Otherwise, the choice between relying on properties and accessing widgets from Python via root.ids is a matter of coding style.

Later in this book, we'll explore more advanced usage of Kivy properties, facilitating nearly effortless data binding.

Layout basics

To arrange widgets on the screen, Kivy provides a number of Layout classes. Layout, a subclass of Widget, serves as a container for other widgets. Every layout affects the positioning and size of its children in a unique way.

For this application, we won't need anything fancy, as the desired UI is pretty straightforward. This is what we're aiming to achieve:

Layout basics

A mockup layout of the finished Clock app interface.

To build this, we will use BoxLayout, which is basically a one-dimensional grid. We already have BoxLayout in our clock.kv file, but since it only has one child, it does not affect anything. A rectangular grid with one cell is really just that, a rectangle.

Kivy layouts almost always try to fill the screen, thus our application will adapt to any screen size and orientation changes automatically.

If we add another label to BoxLayout, it will take half the screen space, depending on the orientation: a vertical box layout grows from top to bottom, and horizontal from left to right.

You might have guessed that in order to create a row of buttons inside a vertical layout, we can just embed another, horizontal box layout into the first one. Layouts are widgets, so they can be nested in arbitrary and creative ways to build complex interfaces.

Finalizing the layout

Stacking three widgets into BoxLayout normally makes every widget a third of the available size. Since we don't want buttons to be this big compared to clock displays, we can add a height property to the horizontal (inner) BoxLayout and set its vertical size_hint property to None.

The size_hint property is a tuple of two values, affecting the widget's width and height. We will discuss the impact that size_hint has on different layouts in the next few chapters; right now, let's just say that if we want to use absolute numbers for width or height, we have to set size_hint to None accordingly; otherwise, assigning size won't work as the widget will continue to compute its own size instead of using the values that we'll provide.

After updating the clock.kv file to account for stopwatch display and controls, it should look similar to the following (note the hierarchy of the layouts):

BoxLayout:
    orientation: 'vertical'

    Label:
        id: time
        text: '[b]00[/b]:00:00'
        font_name: 'Roboto'
        font_size: 60
        markup: True

    BoxLayout:
        height: 90
        orientation: 'horizontal'
        padding: 20
        spacing: 20
        size_hint: (1, None)

        Button:
            text: 'Start'
            font_name: 'Roboto'
            font_size: 25
            bold: True

        Button:
            text: 'Reset'
            font_name: 'Roboto'
            font_size: 25
            bold: True

    Label:
        id: stopwatch
        text: '00:00.[size=40]00[/size]'
        font_name: 'Roboto'
        font_size: 60
        markup: True

If we run the code now, we'll notice that buttons don't fill all the available space inside BoxLayout. This effect is achieved using the padding and spacing properties of the layout. Padding acts very similar to CSS, pushing children (in our case, buttons) away from the edges of the layout, while spacing controls the distance between adjacent children. Both properties default to zero, aiming at maximum widget density.

Reducing repetition

This layout works but has one serious problem: the code is very repetitive. Every change we may want to make has to be done in a number of places throughout the file, and it's very easy to miss one of them and thus introduce an inconsistent change.

Note

To continue the analogy with the web platform, before CSS (Cascading Style Sheets) became universally available, style information was being written directly in tags that surround the text. It looked like this:

<p><font face="Helvetica">Part 1</font></p>
<p><font face="Helvetica">Part 2</font></p>

Using this approach, changing any individual element's properties is easy, but adjusting the properties of the whole document's look requires an excessive amount of manual labor. If we wanted to change the font face to Times in the next version of the page, we would have to search and replace every occurrence of the word Helvetica while trying to make sure that we don't have this same word in the running text, as it may be occasionally replaced too.

With style sheets, on the other hand, we move all of the styling information to a CSS rule:

p {font-family: Helvetica}

Now we have just one place to account for styling of every paragraph throughout the document; no more searching and replacing to change font or any other visual attribute, such as color or padding. Note that we still may slightly adjust a single element's properties:

<p style="font-family: Times">Part 3</p>

So we haven't lost anything by implementing CSS, and there is practically no tradeoff; this explains why the adaptation of style sheets on the Internet was very fast (especially considering the scale) and overwhelmingly successful. CSS is being widely used to this day with no conceptual changes.

In Kivy, there is no need to use a different file for our aggregate styles or class rules, like it's usually done in web development. We just add to the clock.kv file a definition like the following, outside of BoxLayout:

<Label>:
    font_name: 'Roboto'
    font_size: 60
    markup: True

This is a class rule; it acts similar to a CSS selector described in the previous information box. Every Label derives all the properties from the <Label> class rule. (Note the angle brackets.)

Now we can remove the font_name, font_size, and markup properties from each individual Label. As a general rule, always strive to move every repeated definition into a class. This is a well-known best practice called don't repeat yourself (DRY). Changes like the one shown in the previous code snippet may seem trivial in a toy project like this but will make our code much cleaner and more maintainable in a long run.

If we want to override a property of one of the widgets, just add it as usual. Immediate properties take precedence over those inherited from the class definition.

Tip

Keep in mind that a class definition is completely different from a widget defined in the same .kv file. While the syntax is largely the same, the class is just an abstract definition; on its own, it does not create a new widget. Thus, adding a class definition will not introduce any changes to the app if we don't use it later.

Named classes

One obvious problem with the straightforward approach to classes described earlier is that we can only have one class named Label. As soon as we need two different sets of properties applied to the same kind of widget, we have to define our own custom classes for them. Additionally, overwriting the framework's built-in classes, such as Label or Button, may have undesired consequences throughout the application, for example, if another component is using the widget we've altered under the hood.

Fortunately, this is very simple to solve. Let's create a named class for buttons, RobotoButton:

<RobotoButton@Button>:
    font_name: 'Roboto'
    font_size: 25
    bold: True

The part before the @ symbol designates the new class name, followed by the widget type we're extending (in Python, we would say class RobotoButton(Button): instead). The resulting class can be then used in the Kivy language instead of the generic Button class:

RobotoButton:
    text: 'Start'

The use of class rules allows us to reduce the number of recurrent lines in the clock.kv file, and also provide a consistent way of tweaking similar widgets using class definitions. Next, let's use this feature to customize all the buttons.

Styling buttons

One of the darker corners of the flat UI paradigm is the look of clickable elements, like that of buttons; there is no universally accepted way of styling them.

For example, the Modern UI style (previously called Metro, as seen in Windows 8) is very radical, with clickable elements that look mostly like flat-colored rectangles with little or no distinctive graphical features. Other vendors, such as Apple, use vibrant gradients; there is a trend of also adding rounded corners, especially in web design since CSS3 provides a special-case syntax for just that. Subtle shadows, while considered heresy by some, aren't unheard of either.

Kivy is flexible in this regard. The framework does not impose any restrictions on visuals and provides a number of useful features to implement any design you like. One of the utilities that we will discuss next is 9-patch image scaling, which is used to style buttons and similar widgets that may have borders.

9-patch scaling

The motivation for a good scaling algorithm is simple: it's almost impossible to provide pixel-perfect graphics for every button, especially for the problematic ones that contain (varying amounts of) text. Scaling images uniformly is simple to implement but yields results that are mediocre at best, partly because of the aspect ratio distortion.

Non-uniform 9-patch scaling, on the other hand, produces uncompromising quality. The idea is to split the image into static and scalable parts. The following image is a hypothetical scalable button. The middle part (shown in yellow) is the working area, and everything else is a border:

9-patch scaling

The red zones can be stretched in one dimension, while the blue zones (corners) are always left intact. This is evident from the following screenshot:

9-patch scaling

Corners, shown in blue, are fully static and may contain virtually anything. Borders, shown in red, are scalable in one dimension (top and bottom sides can be stretched horizontally, and left and right sides can be stretched vertically). The only part of the image that will be uniformly resized is the inner rectangle, the working area, shown in yellow; it is therefore common to paint it with a flat color. It will also contain text that's assigned to the button, if any.

Using 9-patch images

For this tutorial, we will use a simple flat button with a 1-pixel border. We can reuse this texture for all buttons or choose a different one, for example, for the Reset button. A button texture for the normal state with flat color and 1-pixel border is shown as follows:

Using 9-patch images

The corresponding texture for the pressed state—an inversion of the preceding image—is shown as follows:

Using 9-patch images

Now, to apply the 9-patch magic, we need to tell Kivy the size of borders that have limited scalability, as discussed previously (the image will be scaled uniformly by default). Let's revisit the clock.kv file and add the following properties:

<RobotoButton@Button>:
    background_normal: 'button_normal.png'
    background_down: 'button_down.png'
    border: (2, 2, 2, 2)

The border property values are ordered just like in CSS: top, right, bottom, and left (that is, clockwise starting from the top). Unlike CSS, we can't supply just one value for all sides; at least in the current Kivy version (1.8), the notation border: 2 results in error.

Tip

Probably the shortest way of setting all the borders to the same value is the Python syntax border: [2] * 4, which means take a list with a single element, 2, and repeat it four times.

Also note that while the visible border is just one pixel wide, we're assigning the border property of customized buttons to 2. This is due to the texture-stretching behavior of the renderer: if pixel colors from both sides of the "cut line" don't match, the result will be a gradient, and we want solid color.

In the class rules overview, we mentioned that the property declared on an instance of a widget takes precedence over the class rule's property with the same name. This can be used to selectively override background_*, border or any other attribute, for example, assigning another texture while reusing the border width definition:

RobotoButton:
    text: 'Reset'
    background_normal: 'red_button_normal.png'
    background_down: 'red_button_down.png'

Now our buttons are stylized, but they still don't do anything. The next step towards our goal is making the stopwatch work.

Counting time

Although both stopwatch and the regular clock ultimately just display time, they are completely different in terms of functionality. Wall clock is a strictly increasing monotonic function, while stopwatch time can be paused and reset, decreasing the counter. More practically, the difference is that the operating system readily exposes its internal wall clock to Python, both directly as a datetime object and transparently in the case of the strftime() function. The latter can be called without a datetime argument to format the current time, which is exactly what we need for a wall clock display.

For the task of creating a stopwatch, we will need to build our own, non-monotonic time counter first. This is easily achieved without using Python's time functions altogether, thanks to Kivy's Clock.schedule_interval event handler that accepts the time passed between calls as a parameter. This is just what the nap parameter does in the following code:

def on_start(self):
    Clock.schedule_interval(self.update, 0.016)

def update(self, nap):
    pass

Time is measured in seconds, that is, if the app is running at 60 fps and calls our function every frame, the average nap will be 60−1= 0.016(6).

With this parameter in place, keeping track of the time passed is simple and can be achieved with a simple increment:

class ClockApp(App):
    sw_seconds = 0

    def update(self, nap):
        self.sw_seconds += nap

This timer we just created isn't, by definition, a stopwatch since right now, there is no way for the user to actually stop it. However, let's update the display with the incrementing time first so that we can see the effect of controls immediately when implementing them.

Formatting the time for stopwatch

For the main time display, formatting is easy because the standard library function strftime provides us with a number of readily available primitives to convert a datetime object into a readable string representation, according to the provided format string.

This function has a number of limitations:

  • It only accepts Python datetime objects (while for the stopwatch, we only have a floating-point number of seconds passed, sw_seconds)
  • It has no formatting directive for a decimal fraction of seconds

The former datetime limitation can be easily circumvented: we could cast our sw_seconds variable to datetime. But the latter deficiency makes this unnecessary, as we want to end our notation with fractions of a second (exact to 0.01 sec), so strftime formatting just won't cut it. Hence, we implement our own time formatting.

Computing values

First, we need to compute the necessary values: minutes, seconds, and fractions of a second. The math is easy; here's the one-liner for minutes and seconds:

minutes, seconds = divmod(self.sw_seconds, 60)

Note the use of the divmod function. This is a shorthand for the following:

minutes = self.sw_seconds / 60
seconds = self.sw_seconds % 60

While being more concise, the divmod version should also perform better on most Python interpreters, as it performs the division just once. On today's machines, the floating-point division is quite effective, but if we run a whole lot of such operations every frame, like in a video game or simulation, the CPU time will quickly add up.

Tip

Generally, the author tends to disagree with the oft-chanted mantra about premature optimization being evil; many bad practices that lead to choppy and substandard performance can and should be easily avoided without compromising on code quality, and not doing so is by all means premature pessimization.

Also note that both minutes and seconds values are still floating-point, so we will need to convert them to integers before we print them: int(minutes) and int(seconds).

Now all that's left is hundredths of seconds; we can compute them like this:

int(seconds * 100 % 100)

Putting a stopwatch in place

We have all the values; let's join them together. Formatting strings in Python is quite a common task, and contrary to The Zen of Python commandment that reads, "There should be one—and preferably only one—obvious way to do it" (https://www.python.org/dev/peps/pep-0020/), there are several common idioms for string formatting. We will use one of the simplest, operator %, which is somewhat similar to the sprintf() function commonly found in other programming languages:

def update_time(self, nap):
    self.sw_seconds += nap
    minutes, seconds = divmod(self.sw_seconds, 60)
    self.root.ids.stopwatch.text = (
        '%02d:%02d.[size=40]%02d[/size]' %
        (int(minutes), int(seconds),
         int(seconds * 100 % 100)))

Since we have fractions of a second now, the refresh frequency of 1 fps that we used earlier isn't sufficient anymore. Let's set it to 0 instead so that our update_time function will be called for every frame:

Clock.schedule_interval(self.update_time, 0)

Tip

Today, most displays run at a refresh rate of 60 fps, while our value is exact to 1/100 sec, that is, changes 100 times per second. While we could have attempted to run our function at exactly 100 fps, there is absolutely no reason to do it: for users, it isn't possible to see the difference on commonly available hardware, as the display will still update no more than 60 times per second anyway.

That said, most of the time your code should work independently of a frame rate, as it relies on the user's hardware, and there is no way to predict what machine your application will end up on. Even today's smartphones have wildly different system specs and performance, let alone laptops and desktop computers.

And that's it; if we run the application now, we'll see an incrementing counter. It lacks interactivity yet, and this will be our next target.

Stopwatch controls

Controlling the application by the means of button press events is very easy. All that we need to do for this to work is use the following code:

def start_stop(self):
    self.root.ids.start_stop.text = ('Start'
        if self.sw_started else 'Stop')
    self.sw_started = not self.sw_started

def reset(self):
    if self.sw_started:
        self.root.ids.start_stop.text = 'Start'
        self.sw_started = False
    self.sw_seconds = 0

The first event handler is for the Start and Stop buttons. It changes the state (sw_started) and the button caption. The second handler reverts everything to the initial state.

We also need to add the state property to keep track of whether the stopwatch is running or paused:

class ClockApp(App):
    sw_started = False
    sw_seconds = 0

    def update_clock(self, nap):
        if self.sw_started:
            self.sw_seconds += nap

We change the update_clock function so that it increments sw_seconds only if the stopwatch is started, that is, sw_started is set to True. Initially, the stopwatch isn't started.

In the clock.kv file, we bind these new methods to on_press events:

RobotoButton:
    id: start_stop
    text: 'Start'
    on_press: app.start_stop()

RobotoButton:
    id: reset
    text: 'Reset'
    on_press: app.reset()

Tip

In Kivy language, we have several context-sensitive references at our disposal. They are as follows:

  • self: This always refers to the current widget;
  • root: This is the outermost widget of a given scope;
  • app: This is the application class instance.

As you can see, implementing event handling for buttons isn't hard at all. At this point, our app provides interaction with the stopwatch, allowing the user to start, stop, and reset it. For the purposes of this tutorial, we're done.

Summary

In this chapter, we built a functional Kivy app, ready to be deployed to, for example, Google Play or another app store for public use. This requires a bit of extra work and the process of packaging is platform-specific, but the hardest part—programming—is over.

With the Clock app, we managed to showcase many areas of the Kivy application's development cycle without making the code unnecessarily lengthy or convoluted. Keeping the code short and concise is a major feature of the framework because it allows us to experiment and iterate quickly. Being able to implement new bits of functionality with very little old code getting in the way is invaluable. Kivy surely lives up to its description as a library for rapid application development.

One general principle that we will encounter throughout the book (and Kivy development at large) is that neither our program nor Kivy exist in the void; we always have the whole platform at our disposal, consisting of a rich Python standard library, a lot of other libraries available from the Python cheese shop—the Python Package Index (PyPI) located at http://pypi.python.org—and elsewhere, and the underlying operating system services.

We can also retool many web-development-oriented assets easily, reusing fonts, colors, and shapes from CSS frameworks, such as Bootstrap. And by all means take a look at Google's Material design principles—this isn't just a collection of design assets, but a complete field guide that allows us to achieve a consistent and good-looking UI without sacrificing the identity or "personality" of our application.

This is, of course, only the beginning. Many features that were briefly discussed in this chapter will be explored more in-depth later in this book.

Left arrow icon Right arrow icon
Download code icon Download Code

Description

This book is intended for programmers who are comfortable with the Python language and who want to build desktop and mobile applications with rich GUI in Python with minimal hassle. Knowledge of Kivy is not strictly required—every aspect of the framework is described when it's first used.

What you will learn

  • Set up a development environment for Python and Kivy programming
  • Build crossplatform applications suitable for desktop and mobile
  • Create Modern UI apps reminiscent of Windows Phone flat design
  • Interface with the native Android API to broaden the scope of what functionality is available to your apps
  • Customize your applications by modifying the builtin Kivy features for your project specifications
  • Develop fullstack, clientserver solutions with the backend and UI both written in Python
  • Write modular, reusable code while utilizing various aspects of the Kivy framework
  • Write your own crossplatform videogames, ready for distribution on Google Play, App Store, or even Steam

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Jan 29, 2015
Length: 282 pages
Edition : 1st
Language : English
ISBN-13 : 9781783987849
Category :
Languages :
Tools :

What do you get with a Packt Subscription?

Free for first 7 days. $19.99 p/m after that. Cancel any time!
Product feature icon Unlimited ad-free access to the largest independent learning library in tech. Access this title and thousands more!
Product feature icon 50+ new titles added per month, including many first-to-market concepts and exclusive early access to books as they are being written.
Product feature icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Product feature icon Thousands of reference materials covering every tech concept you need to stay up to date.
Subscribe now
View plans & pricing

Product Details

Publication date : Jan 29, 2015
Length: 282 pages
Edition : 1st
Language : English
ISBN-13 : 9781783987849
Category :
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just NZ$7 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just NZ$7 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total NZ$ 224.97
Kivy Blueprints
NZ$71.99
Kivy Cookbook
NZ$80.99
Kivy ??? Interactive Applications and Games in Python second edition
NZ$71.99
Total NZ$ 224.97 Stars icon
Banner background image

Table of Contents

11 Chapters
1. Building a Clock App Chevron down icon Chevron up icon
2. Building a Paint App Chevron down icon Chevron up icon
3. Sound Recorder for Android Chevron down icon Chevron up icon
4. Kivy Networking Chevron down icon Chevron up icon
5. Making a Remote Desktop App Chevron down icon Chevron up icon
6. Making the 2048 Game Chevron down icon Chevron up icon
7. Writing a Flappy Bird Clone Chevron down icon Chevron up icon
8. Introducing Shaders Chevron down icon Chevron up icon
9. Making a Shoot-Em-Up Game Chevron down icon Chevron up icon
A. The Python Ecosystem Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.7
(10 Ratings)
5 star 40%
4 star 30%
3 star 10%
2 star 0%
1 star 20%
Filter icon Filter
Top Reviews

Filter reviews by




Spartacus Aug 15, 2018
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Book content is great. THIS BOOK is "For sale in India only" see photo. Blacked out but easily read through at an angle with a lamp.Sloooowwww shipping
Amazon Verified review Amazon
Munchkin Jun 06, 2015
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Proved to be very useful so far, providing some info that weren't plainly obvious from the standard tutorials. Anyway I find reading from paperbacks easier than pdfs. Maybe not as advanced as I'd hoped, so there is still a market out there for another book.
Amazon Verified review Amazon
Professor Guvinoff Aug 03, 2015
Full star icon Full star icon Full star icon Full star icon Full star icon 5
The fastest way to learn any tool is to use it. This is as true today in interactive software as it has been all the way back to mastering the plow and building character at the same time. This is the reason I bought this book, and it did not disappoint. After toying with the examples given in the book, one is ready to further explore Kivy and the modern APIs it gives access to. Marl Vasilkov, like all good teachers, knows how to be funny while dealing with the tedium. I enthusiastically give him and his book six stars, because I feel he is one of these perennial children who love exceeding the known limits in everything they do.
Amazon Verified review Amazon
Jorge Carrillo May 16, 2015
Full star icon Full star icon Full star icon Full star icon Full star icon 5
As an experienced Python programmer I'm pretty happy with this book. As others have said this is not a book for beginners. You should know Python and a little bit of Kivy would be helpful as well.The book walks you through developing a series of progressively more challenging applications. The apps interface with other apps as is common these days. I appreciated the author's humor and directness. His explanations demonstrate a good breadth of technical knowledge.I downloaded the git hub code and followed along as I read this book. Other reviewers have commented on the readability of the kv files and their spacing. I had no problems. As far as far as typos in the book, kan anyone spel these days? Also not a big problem.
Amazon Verified review Amazon
Jean-François Parent Apr 09, 2015
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
Kivy Blueprints cover from the ground up the Kivy multi-platform Python applications framework. This book include a lot of examples, some that show you the basic to get started using Kivy and some that illustrate more complex applications. The code's explanation is quite verbose and well written.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is included in a Packt subscription? Chevron down icon Chevron up icon

A subscription provides you with full access to view all Packt and licnesed content online, this includes exclusive access to Early Access titles. Depending on the tier chosen you can also earn credits and discounts to use for owning content

How can I cancel my subscription? Chevron down icon Chevron up icon

To cancel your subscription with us simply go to the account page - found in the top right of the page or at https://subscription.packtpub.com/my-account/subscription - From here you will see the ‘cancel subscription’ button in the grey box with your subscription information in.

What are credits? Chevron down icon Chevron up icon

Credits can be earned from reading 40 section of any title within the payment cycle - a month starting from the day of subscription payment. You also earn a Credit every month if you subscribe to our annual or 18 month plans. Credits can be used to buy books DRM free, the same way that you would pay for a book. Your credits can be found in the subscription homepage - subscription.packtpub.com - clicking on ‘the my’ library dropdown and selecting ‘credits’.

What happens if an Early Access Course is cancelled? Chevron down icon Chevron up icon

Projects are rarely cancelled, but sometimes it's unavoidable. If an Early Access course is cancelled or excessively delayed, you can exchange your purchase for another course. For further details, please contact us here.

Where can I send feedback about an Early Access title? Chevron down icon Chevron up icon

If you have any feedback about the product you're reading, or Early Access in general, then please fill out a contact form here and we'll make sure the feedback gets to the right team. 

Can I download the code files for Early Access titles? Chevron down icon Chevron up icon

We try to ensure that all books in Early Access have code available to use, download, and fork on GitHub. This helps us be more agile in the development of the book, and helps keep the often changing code base of new versions and new technologies as up to date as possible. Unfortunately, however, there will be rare cases when it is not possible for us to have downloadable code samples available until publication.

When we publish the book, the code files will also be available to download from the Packt website.

How accurate is the publication date? Chevron down icon Chevron up icon

The publication date is as accurate as we can be at any point in the project. Unfortunately, delays can happen. Often those delays are out of our control, such as changes to the technology code base or delays in the tech release. We do our best to give you an accurate estimate of the publication date at any given time, and as more chapters are delivered, the more accurate the delivery date will become.

How will I know when new chapters are ready? Chevron down icon Chevron up icon

We'll let you know every time there has been an update to a course that you've bought in Early Access. You'll get an email to let you know there has been a new chapter, or a change to a previous chapter. The new chapters are automatically added to your account, so you can also check back there any time you're ready and download or read them online.

I am a Packt subscriber, do I get Early Access? Chevron down icon Chevron up icon

Yes, all Early Access content is fully available through your subscription. You will need to have a paid for or active trial subscription in order to access all titles.

How is Early Access delivered? Chevron down icon Chevron up icon

Early Access is currently only available as a PDF or through our online reader. As we make changes or add new chapters, the files in your Packt account will be updated so you can download them again or view them online immediately.

How do I buy Early Access content? Chevron down icon Chevron up icon

Early Access is a way of us getting our content to you quicker, but the method of buying the Early Access course is still the same. Just find the course you want to buy, go through the check-out steps, and you’ll get a confirmation email from us with information and a link to the relevant Early Access courses.

What is Early Access? Chevron down icon Chevron up icon

Keeping up to date with the latest technology is difficult; new versions, new frameworks, new techniques. This feature gives you a head-start to our content, as it's being created. With Early Access you'll receive each chapter as it's written, and get regular updates throughout the product's development, as well as the final course as soon as it's ready.We created Early Access as a means of giving you the information you need, as soon as it's available. As we go through the process of developing a course, 99% of it can be ready but we can't publish until that last 1% falls in to place. Early Access helps to unlock the potential of our content early, to help you start your learning when you need it most. You not only get access to every chapter as it's delivered, edited, and updated, but you'll also get the finalized, DRM-free product to download in any format you want when it's published. As a member of Packt, you'll also be eligible for our exclusive offers, including a free course every day, and discounts on new and popular titles.