- Home
- Learn Linux
- Learn Electronics
- Raspberry Pi
- Programming
- Projects
- LPI certification
- News & Reviews
Creating graphical applications using PySide. PySide is a python library for using the Qt Framework. Pyside provides a convenient way of creating GUI applications. Note that much of this applies to other GUI applications, but the implementation would be different if using different programming languages or GUI frameworks. There are some other things that are specific to Python and there are some pitfalls which I explain in the video.
The aim in this video is to show how you can use QThreadPool to ensure the application continues to be responsive when performing other operations. This is not the only option but some way of using an alternative thread or process is needed for most GUI applications.
There are documents online that explain some of this, but I found that they only give very basic examples, and I found it difficult to apply those in my project. So that’s why I thought it would be useful to provide an example how these can be applied.
Create a Signal as a class variable of the MainWindow using:
progress_signal = Signal(int)
Connect the signal to a method using:
progress_signal = Signal(int)
The worker class is created as below
class Worker (QRunnable):
def __init__(self, fn, *args, **kwargs):
super().__init__()
self.fn = fn
self.args = args
self.kwargs = kwargs
@Slot() # Pyside6.QtCore.Slot
def run(self):
self.fn(*self.args, **self.kwargs)
Signals are sent using:
self.progress_signal.emit(self.count)
A thread can be added to the threadpool using:
def button_pressed(self):
worker = Worker(self.run_demo, 5)
self.threadpool.start(worker)
The example code uses time.sleep() to simulate a task that takes a while to run. Note that you would not normally use time.sleep() in a program and that should be replaced with the code you need to run.
The prerequisite for this is Python 3 with Pyside 6. As Pyside 6 is not normally installed it will need to be installed manually. The Raspberry Pi, and some other operating systems, still provide only PySide2 packages in their repositories, therefore you may need to install PySide 6. It's fairly easy, but due to PEP 704 this should normally be done using a virtual environment. The following will setup the environment.
mkdir ~/.venv
python3 -m venv ~/.venv/pyside6
source ~/.venv/pyside6/bin/activate
pip install pyside6
After the packages are installed the code can be run using:
source ~/.venv/pyside6/bin/activate
python3 demo.py
Replace the program file with the file you save it. You can also use an IDE / programming editor such as Thonny or Mu.
In the video I explain how the code is updated from a single threaded application to one using QThreadPool. I have not included the initial code here as the code is deliberately very bad.
Below is the final example which uses QThreadPool, Signals and Slots and creates a worker class to handle the passing of arguments to the thread.
from PySide6.QtCore import Qt, QThreadPool, Signal, Slot, QRunnable
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QLabel, QPushButton, QVBoxLayout
# Only needed for access to command line arguments
import sys
import time
class MainWindow(QMainWindow):
progress_signal = Signal(int)
def __init__(self):
super().__init__()
self.count = 0
self.threadpool = QThreadPool()
self.progress_signal.connect(self.update_display)
self.setWindowTitle("Threaded example")
layout = QVBoxLayout()
self.status_label = QLabel(str(self.count))
self.status_label.setAlignment(Qt.AlignCenter)
self.start_button = QPushButton("Start demo")
self.start_button.pressed.connect(self.button_pressed)
layout.addWidget(self.status_label)
layout.addWidget(self.start_button)
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
def button_pressed(self):
worker = Worker(self.run_demo, 5)
self.threadpool.start(worker)
def run_demo (self, length=10):
for i in range (0, length):
print (f"Sleeping {self.count}")
time.sleep (2)
self.update_count()
def update_display (self, new_num):
self.status_label.setText(str(new_num))
def update_count (self):
self.count += 1
self.progress_signal.emit(self.count)
class Worker (QRunnable):
def __init__(self, fn, *args, **kwargs):
super().__init__()
self.fn = fn
self.args = args
self.kwargs = kwargs
@Slot() # Pyside6.QtCore.Slot
def run(self):
self.fn(*self.args, **self.kwargs)
# Create application
app = QApplication(sys.argv)
# Create a Qt widget for the window
window = MainWindow()
window.show()
# Start the event loop.
app.exec()
At the time of writing the Raspberry Pi includes PySide2, but not the current version which is PySide6. It is likely that the code will work in PySide2, but you will need to change the names for the imported modules (libraries). To run using PySide6 on the Raspberry Pi (and other Debian based Linux distributions) then you can follow the instructions below.
mkdir ~/venv
python -m venv ~/venv/pyside6
source ~/venv/pyside6/bin/activate
pip install pyside6
Then to run use:
source ~/venv/pyside6/bin/activate
python3 demo.py
These are the projects I'm currently working on, although at the time of writing it's early days for both programs.
See my other programming guides at: