Getting Started Writing Qt 6 Applications In Python With PySide6

Christopher Franklin
Weekly Python
Published in
5 min readJan 6, 2021

--

Qt is a cross-platform GUI framework written in C++. It is a powerful way to build desktop applications and with the recent release of Qt 6, it is even better. Additionally, it can be called from a number of other languages using both official and unofficial wrappers. Today we are going to look at the official wrapper for Python, PySide6.

In this tutorial, we are going to build a basic window using the QtWidgets framework. Later tutorials will look at the other ways to build GUI applications with Qt, such as QML and the QtDesigner.

First, you will need to set up a new Python project. I recommend using a virtual environment, but it is completely up to you! Once you have the project folder, run:

pip install pyside6

This will install all the requirements you need to get up and running with a GUI application in Python.

Next, we are going to create a new file in our project folder called main.py and open it in your favorite editor.

Once the file is open we can import everything we will need at the top of it.

import sysfrom PySide6.QtWidgets import QApplication, QWidget, QPushButton

We will use the sys module to safely exit the application when it is closed and free up any remaining system resources. The next 2 lines bring in all the widgets and events we need to build our application from the PySide6 library.

Now we can set up our main loop:

def run():
app = QApplication(sys.argv)
sys.exit(app.exec_())
if __name__ == '__main__':
run()

Here, we define the main block and call our new run function. Inside the run function, we set up a new QApplication and pass in the command line arguments from the system. This main application initializes the Qt Framework and gets it ready to display a new window.

The last line of the run function wraps the call to start the main execution loop of Qt with a sys.exit which makes sure we get back appropriate exit codes.

Now that we have the boilerplate out of the way we can create our main window and add some widgets to it. There are a lot of ways to display windows in Qt, but for now, we are going to stick with the simplest of creating a main QWidget and instantiating it.

class ExampleWindow(QWidget):

The next step is to create our dunder init function:

def __init__(self):
super().__init__()
self.setup()

Inside the initialization, we are calling the parent class __init__ function and then executing a setup method. We will create all the controls inside the setup method and also create the window itself.

To make an empty window, go ahead and define setup as:

def setup(self):
self.setGeometry(100, 100, 200, 150)
self.setWindowTitle('Window Example')

self.show()

This will create an empty window 100 pixels from the top and left corner of the screen and set it to be 200 pixels wide by 150 pixels tall. The window title is also going to show up as Window Example in the title bar.

The final call to self.show() is what actually forces Qt to draw the window to the screen. If you run the application at this point, you will see the window.

Now that we have a basic window showing, let's add a button and link it to the close event. Inside the setup function, above where we define the window, go ahead and add:

btn_quit = QPushButton('Force Quit', self)
btn_quit.clicked.connect(QApplication.instance().quit)
btn_quit.resize(btn_quit.sizeHint())
btn_quit.move(90, 100)

PySide6 knows how to take that button definition and add it to the current window at position (90px, 100px). Unlike other methods of creating a GUI, we don’t need to explicitly add the button to the window here.

In the second line of this example, we are doing something new here. Qt has a built-in eventing system using the concepts of Signals and Slots. In layman terms, we are attaching a call to the quit function into the buttons event slot called clicked .

If you run the application now and click the button, you will see that the window closes as we expect it to.

As a final experiment, lets also override the close event on the window to show a message box! From QtWidgets we need to add an additional import of QMessageBox at the top fo the file.

You will need to also import the QCloseEvent

from PySide6.QtGui import QCloseEvent

The last step is to override the closeEvent method of the QWidget class.

def closeEvent(self, event: QCloseEvent):
reply = QMessageBox.question(
self,
'Message',
'Are you sure you want to quit?',
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)

if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()

This method is called automatically as part of the QCloseEvent chain of events. We can handle the event however we want here, so we interject a new QMessageBox and display it.

The only syntax that might appear weird here is QMessageBox.Yes | QMessageBox.No on line 6 of the example code. Qt follows the patterns established on older system GUI libraries of using an or to join the buttons of the message box we want to display.

When you run the example now, you will see the message box pop up when you close the window and that No is selected by default. If you click yes, you can actually close the application window.

Let’s take one final look at all of the code we just wrote:

import sys

from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QMessageBox
from PySide6.QtGui import QCloseEvent


class ExampleWindow(QWidget):
def __init__(self):
super().__init__()

self.setup()

def setup(self):
btn_quit = QPushButton('Force Quit', self)
btn_quit.clicked.connect(QApplication.instance().quit)
btn_quit.resize(btn_quit.sizeHint())
btn_quit.move(90, 100)

self.setGeometry(100, 100, 200, 150)
self.setWindowTitle('Window Example')

self.show()

def closeEvent(self, event: QCloseEvent):
reply = QMessageBox.question(self, 'Message', 'Are you sure you want to quit?',
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()


def run():
app = QApplication(sys.argv)

ex = ExampleWindow()

sys.exit(app.exec_())


if __name__ == '__main__':
run()

This will give you a good starting point for experimenting with PySide6. I look forward to seeing you in the Python tutorial!

P.S. If you are looking for challenging applications to build in Python, don’t forget to sign up for our free weekly challenge newsletter here!

--

--