- Kivy Blueprints
- Mark Vasilkov
- 871字
- 2021-08-06 19:18:47
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:
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:

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.
- Python編程自學手冊
- Learning PostgreSQL
- arc42 by Example
- C# Programming Cookbook
- Learning SAP Analytics Cloud
- The DevOps 2.4 Toolkit
- Drupal 8 Configuration Management
- Swift語言實戰精講
- FPGA Verilog開發實戰指南:基于Intel Cyclone IV(進階篇)
- HTML5與CSS3基礎教程(第8版)
- 深入實踐Kotlin元編程
- Managing Microsoft Hybrid Clouds
- 軟件體系結構
- Java Web應用開發給力起飛
- 程序員必會的40種算法