Qt is a robust cross-platform framework that works on Windows, Linux, Mac, Android, and more. It allows you to create GUI applications as well as provides libraries for networking,
In this tutorial, we will focus on some of the very core aspects of using PyQt5 and how to package it for distribution.
Here is an example project I created using Pyqt5: https://github.com/DevDungeon/PyQt5-Bitcoin-Price-Checker and the live coding of that project https://www.devdungeon.com/content/live-coding-pyqt5-guis-w-python.
You need the
pyqt5 package for Python and Qt Designer. You can get
both of these by running:
# The primary package with all dependencies pip install pyqt5 # Optional; In Windows, you can get the designer tools from this package pip install pyqt5-tools
You will find the designer in the
site-packages/pyqt5_tools directory of
your Python environment and should be available in your
These packages will also provide
pyuic5 for converting Designer files to Python
files. It also includes many other utilities like
linguist, and more.
If you are using Linux or a system that doesn't have the packages
pyqt5-tools you can usually find the Designer and other apps
in your system's package repositories. For example, in Fedora
there is a package named
You can test your installation by attempting to run the Hello World application in the next section.
Here is a simple example that demonstrates how to initialize a PyQt5 application. It also includes a simple window with nothing in it. A window is not technically required for a PyQt5 application, but generally the primary reason Qt is used is to create GUI windows.
# hello.py import sys from PyQt5.QtWidgets import QApplication, QWidget # Create the main Qt app, passing command line arguments app = QApplication(sys.argv) win = QWidget() win.setWindowTitle('Hello') win.resize(250, 250) win.show() # Run the app, passing it's exit code back through `sys.exit()` # The app will exit when the close button is pressed on the main window. sys.exit(app.exec_())
Run the application like normal using Python:
In Windows, you can use the
.pyw extension or use
pythonw to run the application without the command prompt showing.
Using Qt Designer and .ui files
Using the Designer is optional, but it can be a very helpful way to layout interfaces. I highly recommend using the Designer.
Once you have created a
.ui file in the Designer, you can either
convert it to a Python file which will create the interface programmatically,
or you can load the
.ui file directly. The next sections will cover both options.
Convert UI file to Python code
From the terminal, you can convert a QtDesigner .ui file to a Python file. This method works fine, however it becomes difficult to iterate rapidly on changes with this extra step. You also cannot modify the .py file if you ever want to regenerate it. I recommend using the method in the next section, where you load the .ui file directly.
pyuic5 my_design.ui -o my_window.py python my_window.py
The Python file output will have all the code needed to recreate the interface created in Designer.
Load the UI file in Python
My preferred option for loading interfaces, is to the load the
directly. This means you will need to include the
.ui file with your
distribution, but it means you can easily make changes in the Designer
and quickly test them in Python w/o the extra step of converting the file.
from PyQt5 import uic # If you saved the template in `templates/main_window.ui` ui = uic.loadUi("templates/main_window.ui") # Then you can access the objects from the UI # For example, if you had a label named label1 ui.label1.setText('new text')
Signals are a critical concept to understand when using the Qt framework. Signals and events are similar to channels in Go. Every signal you create must have a data type associated with it. The signal can then emit events that contain data of that type.
For example, if you create a string signal, you can emit strings to anyone listening for the events. You can create an integer signal that spits out integers to listeners. Signals are thread safe.
Alternatively, you can use a decorator
@pyqtSlot(). You can learn more
about that method at
Some widgets come with signals already.
For example, a button comes with a
clicked signal that can be connected.
The next section on threading will provide a working example of how to create a custom signal, connect it to a callback function, and emit events.
To use QThreads, you can create a subclass of
Be sure to call the parent class constructor, and create
any signals that will be used to pass data.
from PyQt5.QtWidgets import QApplication from PyQt5.QtCore import pyqtSignal, QThread import sys class MyTask(QThread): done_signal = pyqtSignal(str) def __init__(self): QThread.__init__(self) def run(self): # Do some work here self.done_signal.emit('some string') def process_done_signal(result): print(result) sys.exit() if __name__ == '__main__': app = QApplication(sys.argv) task = MyTask() task.done_signal.connect(process_done_signal) task.start() # This will continue to run forever, except we are killing the app # in the process_done_signal() function. sys.exit(app.exec_())
Buttons provide some signals out of the box.
For example, the
clicked event is a signal that can be connected
to a callback. For example:
# Assuming you have loaded a `.ui` and stored it in an object named `ui` # and there is a button named `button1` ui.button1.clicked.connect(some_function)
One important thing to keep in mind is that the callback function will block your main application thread, unless it runs the operations in its own thread. See the section above about how to create QThreads. In this example, some_function should kick off a thread to perform operations.
You can package your PyQt5 app in a number of ways including:
- Python setuputils packaging (for
- PyInstaller to create an
.app, or Linux executable
We will only look at using PyInstaller here since regular Python packaging is already well documented.
PyInstaller can be used to create .exe files for Windows, .app files for Mac, and distributable packages for Linux. Optionally, it can create a single file which is more convenient for distributing, but takes slightly longer to start because it unzip itself.
pyi-makespec to generate a
.spec file based on your
You can find more details about spec files at https://pythonhosted.org/PyInstaller/spec-files.html.
# Create a spec file that specifies no console and custom icon # The icon is optional pyi-makespec myapp.py --noconsole --icon=path/to/icon.ico # Or, if you want to create a single file use: pyi-makespec myapp.py --onefile --noconsole --icon=path/to/icon.ico
After generating the spec file, you can customize it to suit your needs.
For example, to add template files, modify the
# Modify the line in the .spec file that has datas= # and include the files to copy over. Put each pair in a tuple. datas=[('templates/*.ui', 'templates')],
Then, after the spec file is complete, you can build it using PyInstaller.
You can get the local documentation on your computer by running the pydoc server and visiting it in your browser.
python -m pydoc -p 8888
Alternatively, you can read the online documentation at https://www.riverbankcomputing.com/static/Docs/PyQt5.
You can find many examples in this GitHub repository: https://github.com/baoboa/pyqt5/tree/master/examples/ and a few examples in the DevDungeon Cookbook.
After working through this tutorial you should have an understanding of how to make basic PyQt5 applications and package them for distribution. PyQt5 is capable of a whole lot more, like system tray icons, dialogs, taking screenshots, drag-and-drop and much more. This tutorial should be enough to just get you started and able to explore more of the available widgets and tools.