avatarEsteban Thilliez

Summary

The provided content is a comprehensive guide on how to create user interfaces in Python using the PyQt library, detailing its installation, basic usage, widgets, layouts, styling, and the concept of signals and slots.

Abstract

The article "How to Build User Interfaces with Python — PyQt Basics" introduces PyQt as a powerful tool for Python developers to move beyond console applications and create graphical user interfaces (GUIs). It compares PyQt to Tkinter, another GUI library, noting PyQt's extensive customization capabilities through style sheets and its use of signals and slots for event handling. The author provides a step-by-step tutorial on setting up a PyQt5 or PyQt6 environment, creating a simple window with a label, and organizing widgets using layouts. The article also covers how to style applications using base styles, color palettes, and CSS-like style sheets, and concludes with an explanation of the signal-slot mechanism, which is crucial for interactive GUI elements. The author, while acknowledging PyQt's complexity and steep learning curve, recommends it over Tkinter for larger, more complex projects due to its versatility and the endless possibilities it offers once mastered.

Opinions

  • The author believes that neither PyQt nor Tkinter is inherently superior, but that the choice should be based on the project's needs.
  • PyQt is described as complex and heavy compared to Tkinter, which is simple and light.
  • The author suggests that while Tkinter is suitable for small, quickly set-up projects, PyQt is preferable for larger or long-term projects due to its extensive possibilities.
  • Learning PyQt is considered to have a steeper learning curve, but the author encourages learning it for the extensive capabilities it provides.
  • The author expresses that mastering PyQt makes GUI creation easier in the long run, despite its initial complexity.
  • The article conveys that understanding signals and slots, although challenging, is key to effectively using PyQt.

How to Build User Interfaces with Python — PyQt Basics

An example of a user interface I built using Python (it’s in french as I am french and built it for me)

Are you tired of all the programs you create running in the console? Try graphical interfaces! It’s very easy to do in Python.

PyQt or Tkinter?

PyQt and Tkinter are the two main libraries you can use to build user interfaces with Python. Neither is better than the other, but depending on what you want to achieve one or the other may be more suitable

Tkinter:

  • Simple and light. This allows you to quickly and easily set up a graphical application.
  • Fewer possibilities than PyQt.
  • GUIs are difficult to customize.
  • Works with events to manage interactions.

PyQt:

  • Complex and heavy. The learning curve isn’t the same as the one of Tkinter but once you master PyQt you can build everything.
  • GUIs are easily customizable using style sheets (CSS).
  • Works with a system of signals and slots which can be a bit confusing for beginners.

It’s good to know both libraries, eventually to know how to use them both, and to decide which one to use depending on the project. Tkinter will be useful for small projects, that need to be set up quickly. PyQt will be preferable when the projects are larger or longer term.

Personally, if you had to learn one of the two, I would recommend PyQt. It takes longer to learn and get the hang of it, but the possibilities are endless when you master it well.

PyQt

Today, I’ll talk only about PyQt as it’s the purpose of the story. I’ll talk about Tkinter in another story.

Installation

You can install either PyQt5 or PyQt6. They are almost the same. PyQt6 is an upgrade of PyQt5 but it doesn’t change a lot of things.

pip install PyQt5
# or
pip install PyQt6

First window

Let’s import some widgets first as we’ll need them to create our window (we’ll see in the next section what widgets are).

from PyQt5.QtWidgets import QApplication, QLabel

A QApplication is a wrapper for a PyQt application. It’s the basic element of every Qt program. Let’s create our application:

import sys

app = QApplication(sys.argv)

Why sys.argv?

These are the arguments passed at the execution of your script. You should know that you have to pass arguments to instantiate a QApplication, at least pass an empty list as an argument.

Now we’ll decorate our application a little:

label = QLabel("Hello")
label.show()

A QLabel is a Qt widget displaying some text? We create it, then call the show method to display it.

Then, we have to execute our application:

app.exec_()

The full code for creating a simple window is:

import sys

from PyQt5.QtWidgets import QApplication, QLabel


app = QApplication(sys.argv)

label = QLabel("Hello")
label.show()

app.exec_()

Widgets

Widgets are everything you see in a PyQt application. If you put text, it is a widget, buttons are widgets, sliders are widgets, etc… Even your window is a widget.

Widgets can be nested within each other. For example, my window is a widget containing other widgets like buttons, which in turn contain widgets like text.

There are a lot of them, and you will certainly use a lot of them if you make a Qt application. We’ll see the QLabel and the QPushButton, for the others, you’ll have to dig into the documentation! (PyQt5 doc)

QLabel

It is simply a widget containing text. We pass the text to display when we build it.

label = QLabel("Hello")

QPushButton

It is a widget representing a button. In the same way as a QLabel, we pass it the text of the button.

button = QPushButton("I'm a button!")

Is that all? How do you assign actions when you click on the button?

We’ll see later when we’ll study the signals and the slots :)

Layouts

Layouts are also widgets. However, they are a bit special because they have no graphical appearance. They simply tell you how to arrange the widgets in the window.

For example, imagine that you have a cabinet with several drawers. This cupboard can have several doors, several drawers, etc… And you can store objects in them in the dedicated slots. In this case, your items will be well organized and arranged according to the structure defined by the cabinet.

This is pretty much what you can do with layouts, except that, unlike the wardrobe, the layouts and drawers are invisible, only the objects contained in them are visible.

Let’s start by creating our first layout, a QVBoxLayout. This is a layout that allows us to stack widgets on top of each other.

from PyQt5.QtWidgets import QVBoxLayout


vbox = QVBoxLayout()

Now that we have created our vertical storage cabinet, we need to fill it with items.

button1 = QPushButton("Button 1")
button2 = QPushButton("Button 2")
vbox.addWidget(button1)
vbox.addWidget(button2)

Our cabinet is filled with two buttons that will be displayed vertically. But now, what do we do? Our wardrobe has to be in a house to be useful (well, not necessarily, but logically so). Our house is the window of the application, it is in it that we can put all our wardrobes. Be careful though, we have to distinguish the window from the application.

We start by creating an application, in which we create a window, and to which we add our cabinet (layout). Finally, we display our window, and we execute the whole thing:

from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton


app = QApplication([])

window = QWidget()

vbox = QVBoxLayout()

button1 = QPushButton("Button 1")
button2 = QPushButton("Button 2")

vbox.addWidget(button1)
vbox.addWidget(button2)

window.setLayout(vbox)

window.show()
app.exec()

Run this code and you’ll see a beautiful window containing two buttons.

Styling your app

If you want to style your app, you can do it in several ways:

  • Base styles.
  • Colors palettes.
  • Style sheets.

Base styles

PyQt offers several basic styles, which can be switched easily. They completely change the appearance of your application. Here are some of them:

  • Fusion
  • Windows
  • WindowsVista
  • Macintosh
  • etc…

To apply a style, we use the method setStyleof our application:

app.setStyle("Windows")

Colors palettes

Maybe you just want to change the colors instead of redesigning the whole style. For this we use QPalette. It allows you to do the color mapping. For example:

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPalette


palette = QPalette()
palette.setColor(QPalette.ButtonText, Qt.green)
app.setPalette(palette)

In this example, we changed the color of every button’s text in our application and set it to green.

You can find all possible mappings in QPalette documentation.

Style sheets

Finally, the most complete way to modify the design of a PyQt application is by using style sheets. To do this, simply store your stylesheet in a string, and modify the style like this:

stylesheet = "QPushButton { margin-bottom: 5ex; }"
app.setStyleSheet(stylesheet)

So, you can create a .css file, fill it with styles and then you extract its content and use it as a PyQt style sheet.

Signals and slots

These concepts are perhaps the hardest to understand in PyQt. A signal is sent when an action is performed, and a slot is an action that executes in response to that signal. For example, when a button is clicked, it sends a signal to say that the button was clicked, and it is possible to connect that to a slot to display text in response to that click, or to start a download, etc…

PyQt offers many signals with its widgets. For example, the signal mentioned above can be retrieved in this way:

button = QPushButton("Hello")
button.clicked.connect(...)

So, we have this syntax: widget.signal.connect(function) .

If I want to display console text when I click on my button, I do it this way:

def hello():
    print("hello")

button.clicked.connect(hello)

You always have to connect a function. So if I try to do this:

button.clicked.connect(hello())

I will get an error because hello() is not a function, but the value returned by hello. So this is where lambda functions become useful, so you can avoid writing too many basic functions.

button.clicked.connect(lambda x: print("hello"))

You can find more information about the signals of each widget in the PyQt documentation!

Final note

There is so much to say about PyQt. I can’t tell you anything in one story, perhaps there will be more. While waiting, just practice because this library may be hard to understand but once you get the trick everything becomes easier.

Good luck with PyQt!

Python
User Interface
User Experience
Programming
Software Development
Recommended from ReadMedium