Programação RPi Python 11: GUI Python com Tkinter

RPi Python 11 Programming: Python GUI with Tkinter

In the previous tutorial , we learned about Python's object-oriented features, which are important for organizing code and structuring our applications. Now, let's discuss how to design graphical interfaces in Python.

Embedded applications developed on microcontrollers typically have LEDs, character LCDs, or small graphic LCDs as display devices. However, these monitors don't have many sophisticated interfaces. But a single-board computer (like Raspberry Pi) can be configured as a desktop system. We actually set up our Raspberry Pi (RPi) using a Linux desktop. As such, it is possible to enjoy rich interfaces and large applications running on similar embedded circuits.

While microcontrollers offer speed, single-board computers have advantages that include an operating system with easy access to high-level language features. Rich graphical interfaces, database access, data visualization, 3D graphics, networking, and data mining are just some of the HLL features that can be used in an embedded project with SBCs.

For example, by interfacing a sensor with a microcontroller, we can just collect data from the sensor and implement immediate actions based on the collected data. However, if this same sensor is interconnected with a single board computer (SBC), it is possible to perform several tasks.

These include:

  • Record and maintain large amounts of sensor data in databases
  • Running analyzes
  • Viewing data
  • Performing data mining
  • Sharing data and any results with other devices on a network
  • Implement immediate and long-term actions

A microcontroller-based device running on firmware-level code cannot perform these complex tasks on its own. At most, it can be configured as an Internet of Things (IoT) device by connecting it to a network. The collected physical data can then be manipulated on a cloud platform. This is a big reason why single board computers have a distinct role in the embedded domain.

Another reason: users work with hardware-software co-design on embedded systems when working on SBCs. Although microcontroller-based applications focus on hardware, the user can shift focus to software aspects. SBCs enable the creation of high-level embedded software that utilizes the power of a hardware component.

Ultimately, it's the software running on the hardware that makes the most sense. The interface and control of LEDs is the “Hello World” of embedded systems.

Below is a screenshot of a graphical user interface (GUI) designed for our first LED driver recipe. Take a minute to review this GUI and try to guess the level of control we can exert over a hardware component with an SBC.

The Python Tkinter GUI for an RPi LED driver.

In all of our RPi recipes, we often use GUI programming and multithreading. When using sensors, we will include data visualization, database programming and data mining in the embedded software.

Similarly, when we control actuators, build robots, or use sophisticated hardware modules (like a camera or microphone, etc.), it is possible to include relevant software features such as image processing, audio, multimedia programming, 3D graphics, and software programming. games. , etc.

GUI programming and multithreading are essential software components of all our recipes.

GUI Programming in Python
Python is a powerful very high-level language (VHLL). It enables the design of rich graphical interfaces and provides a series of data visualization techniques with data mining capabilities. This is a distinct advantage in sophisticated embedded applications.

When using RPi in embedded applications, we will treat embedded circuits as physical data sources (when interconnected with sensors) and sophisticated controllers (when interconnected with actuators).

Graphical interfaces designed in Python interact with embedded circuits, visualize data from sensors, manipulate data for analysis and decision making, and provide additional interactivity not typically possible with microcontrollers.

Python Tkinter GUI main window for the RPi embedded electronics application.

There are several options in Python for developing graphical user interfaces. The most popular include:

Tkinter - the standard Python interface for the Tk GUI toolkit and the de facto GUI standard in Python. Tkinter is free and automatically included with the Python installation on Linux, Microsoft Windows, and Mac OS X. To use it in an application, however, the Tkinter package must be imported.

WxPython – an open source, cross-platform GUI toolkit for Python. Its main advantage is native widgets (OS-specific native widgets).

PyQT – binding for the Qt cross-platform GUI toolkit. It is probably the most powerful and substantial GUI for Python. PyQT is ideal for large applications and is available under GPL and commercial licenses. Can be complicated to use for commercial applications.

PySide – similar to PyQT in functionality, but PySide is covered by the LGPL license. Therefore, it is readily available for use in commercial applications.

There are many other GUI packages for Python. Before using an app, it's important to learn about its features, portability, development tools, licensing, and limitations. For large applications, PyQT and PySide are usually the best options (and PySide has a more liberal license).

There are also WYSIWYG editors available for PyQT and PySide that make designing interfaces quick and easy. Tkinter is the best choice for basic applications.

We will use Tkinter to design the GUI for RPi recipes. It takes up little space with relatively fast execution compared to other packages. Layout management is also quite efficient. These features make Tkinter an ideal option for embedded UI.

However, we will have to write code for each widget and handling events is sometimes complicated. These efforts will be to speed up our small embedded applications.

Built-in multithreading tasks

In embedded applications, it is common to repeat certain tasks. For example, we may need to repeatedly fetch data from a sensor or display messages on a display device. But desktop applications rarely involve such tasks — you would never want a desktop application's code to run in a never-ending infinite loop.

In our RPi recipes, we will implement infinite loops typical of embedded applications. However, if we run these loops from the GUI application, our interface will freeze and we will not be able to enter any other commands.

So for each embedded task we will create a separate thread and the GUI will run as a different process in Linux. We can pass commands to kill these threads with a little coding trick to stop tasks whenever necessary. With threads, we can treat RPi recipes like microcontroller-based embedded applications, but more efficiently.

With multithreading, there are also the advantages of simultaneously and independently handling multiple hardware components. Multi-threading is not possible on microcontrollers, which just goes to show that the SBC running an embedded operating system is critical.

Tkinter
Tkinter is the standard GUI library for Python. It provides an object-oriented interface to the Tk GUI toolkit. Any GUI consists of a main window in which different graphical elements – such as labels, text boxes, buttons, radio buttons, check buttons, screens, etc. – are displayed.

These graphical elements, including the main window and other windows, are called widgets. User actions like clicking a button, focusing on a text box, selecting a radio button, etc. are called events. In response to an event, it is possible to open another window, which is then called the child window of the parent window.

To create a user interface with Tkinter, first import the Tkinter module, which can be done in Python code like any other module. The module name is “Tkinter” in Python 2 and “tkinter” in Python 3.

These are valid instructions for importing the Tkinter module in Python 3:

import tkinter

or
from tkinter import *
or
import tkinter as tk

In the third example above, “tk” is the reference defined for the Tk class. This reference can be any identifier. After importing the Tkinter module, create a main GUI application window. This can be done by creating an instance object of the Tk class. For the main window (which is not a child of any other window), the Tk object is created without any arguments.

These are valid statements to create the main window

root = Tk

or
root = tkinter.Tk

or
root = tk.Tk # tk is reference to Tk class in import statement

To create a child window, the instance object with the Toplevel method must first be created – which must be passed to the parent window (object) as an argument.

Here is a valid statement to create a child window:

LED_window = top level (root)

All window widgets, including the main window, support multiple methods. Of all the methods, the main loop method is the most important.

Until the mainloop method is called on a window widget, it will not appear on the screen. The mainloop method starts an infinite loop to run the GUI window, wait for an event to occur, and process the event while the window is not closed.

Therefore, the mainloop method must be the last instruction to be called in a window widget. Any other methods called on the widget after mainloop will not be executed and will return an error.

These are valid statements to launch the main Tkinter window:

root = Tk
root.mainloop

These are valid instructions for starting a child window:

LED_window = top level (root)
LED_window.mainloop

A window can be destroyed by calling the destroy method.

Here is a valid instruction for destroying a window (called window):

window.destroy

The style and behavior of a window can be changed by calling different methods. For example, to set the window title, the title method is available.

This is a valid statement for setting the title of a window (called window):

window.title (“Raspberry Pi Embedded Electronics Control Application”)

To define the size and position of the window on the screen, the geometry method can be used. The geometry method can take four optional arguments as follows:

window.geometry(“widthxheight+/-horizontal_position+/-vertical_position”)

This is a valid statement to define the size and position of a window (called a window):

window.geometry (“300×300+100+50”)

All four arguments (window width, window height, horizontal position, and vertical position) accept integer values ​​in pixels.

Observation:

  • If the horizontal position has a plus sign on the left, the left edge of the window will be so many pixels from the left edge of the screen.
  • If the horizontal position has a minus sign on the left, the right edge of the window will be so many pixels from the right edge of the screen.
  • Likewise, if vertical has a left plus sign, the top edge of the window will be so many pixels from the top edge of the screen, and if vertical has a left minus sign, the bottom edge of the window will have this number of pixels. from the bottom edge of the screen.

The minimum and maximum size of a window can also be set using the minsize and maxsize methods. Both methods take the width and height of the window in pixels and as arguments.

Here is a valid statement to set the minimum size of a window (called a window):

window.minsize(480, 480)

By default, a window is resizable and a user can change the size of the window by dragging its borders. A window's resizing behavior can be changed using the resizable method.

This method takes two Boolean arguments to set the width and height of the resizable window to True or False.

The Tkinter module also allows the creation of static interfaces. When the user resizes a window, its layout may become clumsy due to the static nature of the interface. Therefore, it is advisable to set the resizability of a window to False as follows:

window.resizable (False, False)

A window automatically resizes according to the child widgets it contains. If the maximum size is set for a window, some of the child widgets may not be visible. As a result, it is never recommended to set the maximum size of a window.

A window can have multiple states, such as:

  • Normal – displayed on the screen in its default size and position
  • Enlarged – displayed covering the entire screen
  • Icon – minimized to taskbar
  • Removed – window closed

By default, the window appears in its “normal” state. If it is set to resize horizontally and vertically, it can be enlarged to full screen size by clicking the maximize button. It can also be “zoomed” from within the code by setting it to its state, such as:

window.state('enlarged')

A window can be minimized to the icon by clicking the minimize button. It can be minimized to an icon from within the code using the iconify method or by setting its state to 'icon' as follows:

window.state('icon')

or
window.iconify

A window can be restored to its normal state by clicking its icon on the taskbar. It can be restored to a normal state from within the code using the deiconify method or by setting its state to “normal:”

window.state('normal')

or
window.deiconify

We will be using the ttk themed widgets in our GUI windows. ttk is a separate module that provides access to Tk themed widgets. It separates the code that implements the appearance of the widgets as well as the code that implements the behavior of the widgets.

This means we will need to import ttk separately with Tkinter. Here are valid instructions for importing ttk:

import ttk
or
ttk import *
or
from tkinter import ttk
The following are valid instructions for starting a blank main window:
from tkinter import *
from tkinter import ttk
root = Tk
root.title (“RPi Embedded Electronic Control APP”)
root.minsize(480, 480)
root.resizable(0, 0)
root.mainloop

This is a blank main GUI window that contains no other widgets. Note that the mainloop method is called in the last statement of the main window.

Python Tkinter GUI main window menus for an RPi embedded electronics application.

Stay connected. You are about to witness a multithreading approach to embedded applications using Raspberry Pi. We will be controlling the embedded circuits through a desktop GUI application while implementing the microcontroller's embedded operations on a single board computer.

In the next tutorial , we will learn more about Tkinter and ttk widgets by adding a menu to our RPi embedded electronic control application. We will also continue adding GUI frames to our application for each embedded electronic component (display devices, sensors, modules, motors, and communication interfaces) controlled by the application.

Back to blog

Leave a comment

Please note, comments need to be approved before they are published.