39.3 Einführung in PyQt 

Im vorangegangenen Abschnitt wurde das Modul tkinter besprochen, mit dessen Hilfe sich Tk-GUIs unter Python schreiben lassen. Der große Vorteil von tkinter ist, dass es in der Standardbibliothek enthalten ist und somit nicht separat installiert werden muss. Demgegenüber steht, dass Tk nicht mehr zeitgemäß ist und sich eher zum Schreiben von Prototypen oder kleineren GUI-Anwendungen eignet. Als Gegenpol zu Tk erhalten Sie in diesem Abschnitt eine projektorientierte Einführung in das umfangreiche Qt-Framework.
Sie haben in Abschnitt 39.1, »Toolkits«, bereits einen Überblick darüber erhalten, was das Framework Qt[ 191 ](sprich cute, dt. »süß«, »pfiffig« ) und damit auch die Python-Bindings PyQt ausmacht. Dieser grobe Überblick wird hier verfeinert, wobei wir die Konzepte und Stärken von Qt vor allem von der technischen Seite her beleuchten werden.
Dazu beschäftigen wir uns im nächsten Abschnitt zunächst mit der Frage, wo und wie Qt und PyQt bezogen und installiert werden können. Danach geben wir Ihnen eine Übersicht über die grundlegenden Konzepte des Qt-Frameworks.
39.3.1 Installation 

Wenn Sie Anaconda einsetzen, ist PyQt bereits standardmäßig installiert oder kann wie in Abschnitt 38.4 beschrieben nachinstalliert werden:
$ conda install pyqt
Für Leser, die Anaconda nicht einsetzen
Um PyQt manuell einzurichten, müssen zwei Komponenten installiert werden: das Qt-Framework und die zugehörigen Python-Bindings. Sollten Sie beides noch nicht auf Ihrem PC installiert haben und ein Windows-Betriebssystem einsetzen, können Sie das Komplettpaket von der Website des PyQt-Entwicklers herunterladen: http://www.riverbankcomputing.com.
Wenn aus gewissen Gründen das Komplettpaket für Sie nicht infrage kommt, können Qt und PyQt auch getrennt voneinander installiert werden. Sie können sich Qt von der Website http://www.qt.io kostenlos herunterladen.
Falls Sie Linux einsetzen, lohnt es sich, in den verfügbaren Paketen Ihrer Distribution nachzuschauen, ob PyQt dort verfügbar ist. Unter Ubuntu können Sie PyQt beispielsweise folgendermaßen installieren:
$ sudo apt-get install python3-pyqt5
[»] Hinweis
Sollten Sie während der Installation von Qt unter Windows eine Warnung bekommen, dass keine MinGW-Installation auf Ihrem Rechner gefunden wurde, können Sie diese ignorieren, sofern Sie ausschließlich mit PyQt arbeiten möchten. MinGW ist eine freie Compiler-Distribution für C und C++.
39.3.2 Grundlegende Konzepte von Qt 

Als Einführung in die Programmierung mit Qt bzw. PyQt erhalten Sie in diesem Abschnitt eine Übersicht über die wichtigsten Konzepte und Stärken des Qt-Frameworks.
Lizenz
Qt und PyQt stehen unter einem dualen Lizenzsystem. Projekte, die Sie mit den angebotenen freien Versionen von Qt und PyQt entwickeln, dürfen Sie nur unter einer ebenfalls freien Lizenz, beispielsweise der GPL, veröffentlichen. Um ein kommerzielles Programm veröffentlichen zu dürfen, muss eine Lizenzgebühr entrichtet werden.
Umfang
Ihnen wird bereits aufgefallen sein, dass im Zusammenhang mit Qt nicht von einem Toolkit, sondern von einem Framework gesprochen wurde. Das hängt damit zusammen, dass der überwiegende Teil der Klassen, die das Qt-Framework enthält, nichts mit der Programmierung grafischer Benutzeroberflächen zu tun hat, sondern anderweitige nützliche Funktionen bereitstellt. So enthält das Qt-Framework beispielsweise Klassen zur Arbeit mit XML-Daten oder zur Netzwerkkommunikation. Viele dieser Klassen sind zwar in Kombination mit Python aufgrund der Standardbibliothek faktisch überflüssig, bieten aber in Programmiersprachen wie C++, die nicht über so umfangreiche Standardbibliotheken verfügen, einen erheblichen Mehrwert.
Signale und Slots
Einer der größten Unterschiede zu anderen GUI-Toolkits ist das Signal-und-Slot-Prinzip, das Qt zur Kommunikation einzelner Objekte untereinander einsetzt. Bei jedem Ereignis, das in einem Qt-Objekt auftritt, beispielsweise beim Anklicken einer Schaltfläche, wird ein Signal gesendet, das dann von verbundenen Slots empfangen werden kann. Signale und Slots sind flexibler als das Überladen von Methoden, das in anderen Toolkits zur Kommunikation verwendet wird.
Näheres zum Signal-und-Slot-Prinzip erfahren Sie in Abschnitt 39.4.
Layouts
Das Qt-Framework unterstützt Layouts in der grafischen Oberfläche eines Programms. Mithilfe eines Layouts lassen sich Steuerelemente relativ zueinander automatisch positionieren. Diese Gruppe von Steuerelementen kann dann gemeinsam verschoben oder in der Größe verändert werden, ohne ihre relative Ausrichtung zueinander zu verlieren.
Näheres zu Layouts erfahren Sie in Abschnitt 39.3.3, »Entwicklungsprozess«.
Zeichenfunktionen
Qt stellt umfangreiche Funktionalität zum Zeichnen in der grafischen Benutzeroberfläche bereit. So erlaubt Qt das Zeichnen verschiedenster Formen mit verschiedensten Arten der Füllung oder des Linienstils. Darüber hinaus bietet Qt Möglichkeiten zur Transformation von Zeichnungen mithilfe von Transformationsmatrizen, was erstaunliche Effekte ermöglicht und wodurch sich Qt von vielen anderen GUI-Toolkits abhebt. Ebenso ermöglicht Qt das Lesen und Schreiben vieler Grafikformate, darunter vor allem auch des Vektorformats SVG.
Näheres zum Zeichnen mittels Qt erfahren Sie in Abschnitt 39.6, »Zeichenfunktionalität«.
Das Model-View-Konzept
Qt implementiert das Model-View-Konzept, das eine Trennung von Form und Inhalt ermöglicht. So ist es in Qt möglich, die Daten, die ein Programm verarbeitet, in einer eigenen Klassenstruktur zu speichern – getrennt von der Funktionalität, die diese Daten anzeigt. Auf diese Weise wird der Programmaufbau insgesamt übersichtlicher, und die unabhängige Weiterentwicklung und Wiederverwertung einzelner Komponenten werden erleichtert.
Näheres zum Model-View-Konzept erfahren Sie in Abschnitt 39.7.
QML
Seit Version 4.7 enthält Qt mit QML eine an CSS angelehnte Skriptsprache, die das Gestalten grafischer Oberflächen und das Erstellen einfacher Programmlogiken auf abstrakter Ebene ermöglicht.
Werkzeuge
Der nächste herausragende Bereich von Qt sind die mitgelieferten Werkzeuge. Bei einer Qt-Installation werden für gewöhnlich die Programme Qt Designer, Qt Assistant und Qt Linguist mit installiert. Ersteres ist ein Programm zur komfortablen Gestaltung grafischer Benutzeroberflächen. Wir werden im Laufe dieses Kapitels noch auf den Qt Designer zurückkommen.
Die ebenfalls mitgelieferten Programme Qt Assistant und Qt Linguist werden in diesem Buch nicht besprochen. Es sei nur erwähnt, dass es sich bei Qt Assistant um ein Tool zum Lesen der Qt-Hilfe und bei Qt Linguist um ein Hilfsmittel zur Lokalisierung von Qt-Anwendungen handelt.
Dokumentation
Als letzter Punkt ist die Dokumentation des Qt-Frameworks zu nennen, die entweder Ihrer Qt-Installation beiliegt oder im Internet unter http://doc.qt.io zu finden ist. Die Qt-Dokumentation ist sehr umfangreich und mit vielen Beispielen versehen.
Mit der PyQt-Installation erhalten Sie zudem eine auf Python abgestimmte Version der Qt-Dokumentation, in der alle Schnittstellen und ein Teil der Beispiele für Python beschrieben werden. Auch diese Dokumentation ist mittlerweile umfangreich genug, um mit ihr arbeiten zu können. Beachten Sie, dass in der PyQt-Dokumentation viele Beispiele noch nicht von C++ nach Python übersetzt worden sind.
39.3.3 Entwicklungsprozess 

In diesem Abschnitt wird der vollständige Entwicklungsprozess einer einfachen PyQt-Anwendung dargestellt. Auf dem hier erarbeiteten Wissen werden wir später aufbauen, wenn es an eine komplexere Anwendung geht.
Bei dem Beispielprogramm, das in diesem Abschnitt entwickelt wird, handelt es sich um ein Formular, das einige persönliche Daten vom Benutzer einliest.
Der Dialog
In diesem Beispiel sollen Vorname, Nachname, Geburtsdatum und Adresse des Benutzers eingelesen und gespeichert werden. Zusätzlich soll der Benutzer die allgemeinen Geschäftsbedingungen unseres Pseudoportals akzeptieren müssen und optional einen Newsletter bestellen können.
Auf Basis dieser Voraussetzungen können wir im nächsten Schritt einen Dialog erstellen. Ein Dialog ist ein einzelnes Fenster einer grafischen Oberfläche und enthält mehrere Widgets. Unter einem Widget (dt. »Dingsbums«) versteht man ein einzelnes Steuer- oder Bedienelement der grafischen Oberfläche. Ein Widget kann beliebig viele untergeordnete Widgets enthalten, sogenannte Children (dt. »Kinder«). Im Dialog aus Abbildung 39.35 sind beispielsweise die Eingabefelder, die ihrerseits ebenfalls Widgets sind, dem Gruppierungswidget Persönliche Daten untergeordnet.
Abbildung 39.35 zeigt den Hauptdialog unserer ersten Anwendung und erklärt die Namen und Bedeutungen der einzelnen Widgets.
Jetzt können wir damit beginnen, den Dialog zu erstellen. Qt stellt dafür ein komfortables Entwicklungswerkzeug, den Qt Designer, bereit. Mithilfe des Qt Designers lassen sich auch komplexe Dialoge problemlos editieren.
Unter Windows finden Sie das Programm Qt Designer im Startmenü unter dem Eintrag Qt bzw. PyQt. Sollten Sie Linux oder macOS einsetzen, müssen Sie den Qt Designer gegebenenfalls über den Befehl designer aus einer Shell heraus starten.
Abbildung 39.35 Die verschiedenen Widgets des Hauptdialogs
Nach dem Starten des Designers wird die Möglichkeit angeboten, ein sogenanntes Template (dt. »Schablone«) zu laden. Wir entscheiden uns in diesem Fall für das Template Dialog without buttons, das einen vollständig leeren Dialog bereitstellt. Danach präsentiert sich der Qt Designer so wie in Abbildung 39.36.
Abbildung 39.36 Der Qt Designer
Die Arbeitsfläche des Qt Designers lässt sich grob in drei Bereiche unterteilen:
- In der Mitte finden Sie Ihre Dialogvorlage, die zu diesem Zeitpunkt noch leer ist.
- Auf der linken Seite befindet sich eine Liste aller verfügbaren Steuerelemente. Um eines dieser Steuerelemente zum Dialog hinzuzufügen, wählen Sie es aus und ziehen es auf den Dialog. Nachdem ein Steuerelement zum Dialog hinzugefügt worden ist, kann es beliebig positioniert oder in seiner Größe verändert werden.
- Auf der rechten Seite können die Eigenschaften des aktuell ausgewählten Steuerelements bearbeitet werden.
Wir beginnen damit, die beiden Schaltflächen OK und Abbrechen im Dialog zu platzieren. Dazu ziehen Sie zwei Buttons aus der Liste am linken Rand und platzieren sie im Dialog. Die Aufschrift der Schaltflächen lässt sich durch einen Doppelklick auf den bisherigen Text verändern. Um die Schaltfläche OK zur Standardschaltfläche des Dialogs zu machen, ändern Sie die Eigenschaft default des Buttons in der Liste auf der rechten Seite auf true. Ziehen Sie danach zwei Groupboxen auf den Dialog, und passen Sie Größe und Position Ihren Wünschen an. Den Titel einer Groupbox können Sie durch einen Doppelklick auf den bisherigen Text anpassen (siehe Abbildung 39.37).
Abbildung 39.37 Dialog mit Groupboxen
Jetzt könnten im Prinzip weitere Widgets zum Dialog hinzugefügt werden, indem sie in eine der beiden Gruppen platziert werden. Das macht sie automatisch zu untergeordneten Widgets, die in ihrer jeweiligen Gruppe absolut positioniert werden. Damit sich die untergeordneten Widgets bei einer Größenänderung des Hauptdialogs automatisch anpassen, erstellen wir für sie ein Layout. Um ein Layout zu erstellen, markieren Sie alle Widgets, die dazugehören sollen, und wählen eine der Schaltflächen aus der Layout-Toolbar (siehe Abbildung 39.38).
Abbildung 39.38 Die Layout-Toolbar
Ein Klick auf das erste Icon ordnet die Steuerelemente horizontal an, ein Klick auf das zweite Icon vertikal. Die beiden folgenden Icons erstellen einen Splitter (dt. »Trenner«) zwischen den Steuerelementen, der später vom Benutzer verschoben werden kann. Dies ist für unseren Dialog nicht weiter wichtig, deshalb benötigen wir den Splitter nicht. Interessant ist noch die fünfte Schaltfläche, die die markierten Steuerelemente tabellarisch anordnet. Ein Klick auf das letzte Icon löst ein bestehendes Layout auf.
Mithilfe von Layouts lässt sich die oben dargestellte absolute Anordnung von Groupboxen bzw. Buttons zu einem vollwertigen Dialog machen, dessen Elemente sich bei einer Größenveränderung automatisch mit anpassen. Dazu werden die beiden Buttons, inklusive eines Spacers für den linken Rand, horizontal angeordnet. Die Groupboxen und das Button-Layout werden dann in einem übergeordneten Layout vertikal angeordnet:
Abbildung 39.39 Das Basislayout
In analoger Weise können die weiteren Steuerelemente des geplanten Dialogs eingefügt und mit Layouts versehen werden. Um den Text der Label-Widgets zu bearbeiten, klicken Sie wie bei einer Groupbox doppelt auf den bisherigen Text. Der fertige Dialog sieht im Designer folgendermaßen aus:
Abbildung 39.40 Das fertige Layout
Damit ist der Dialog äußerlich gestaltet, doch eine wichtige Sache fehlt noch. Jedes Steuerelement benötigt einen Namen, unter dem es nachher im Programm angesprochen werden kann. Diesen Namen können Sie im Qt Designer festlegen. Um einem Widget einen neuen Namen zu verpassen, markieren Sie es, öffnen mit einem Rechtsklick das entsprechende Kontextmenü und wählen den Menüpunkt Objektnamen ändern.
Tabelle 39.11 listet die im Beispiel vergebenen Namen für alle wichtigen Steuerelemente auf. Steuerelemente, die nur aus Layoutgründen existieren, beispielsweise die Groupboxen und Labels, müssen nicht benannt werden, da später keine Operationen mit ihnen durchgeführt werden.
Steuerelement | Name |
---|---|
der Dialog selbst | Hauptdialog |
das Line-Edit-Widget »Vorname« | vorname |
das Line-Edit-Widget »Nachname« | nachname |
das Date-Edit-Widget »Geburtsdatum« | geburtsdatum |
das Text-Edit-Widget »Adresse« | adresse |
das Check-Box-Widget »AGB« | agb |
das Check-Box-Widget »Katalog bestellen« | katalog |
das Button-Widget »OK« | buttonOK |
das Button-Widget »Abbrechen« | buttonAbbrechen |
Tabelle 39.11 Die Namen der wichtigen Steuerelemente
Nachdem alle Namen vergeben wurden, ist das Layout des Hauptdialogs fertig und kann im Projektverzeichnis gespeichert werden. Im Falle dieses Beispielprogramms soll der Dialog unter dem Dateinamen hauptdialog.ui gespeichert werden.
Das Programm
Es gibt zwei Wege, den erstellten Dialog aus einem Programm heraus zu nutzen:
-
Der in einer UI-Datei gespeicherte Dialog kann mithilfe des bei PyQt mitgelieferten Programms pyuic5 in eine Python-Klasse überführt werden. Diese Klasse kann dann von einem Programm eingebunden und verwendet werden. Das Programm pyuic5 bekommt den Pfad zur UI-Datei als Kommandozeilenparameter übergeben und gibt die daraus erstellte Python-Klasse standardmäßig auf dem Bildschirm aus. Um die Ausgabe in eine Programmdatei umzulenken, können Sie die Kommandozeilenoption -o verwenden:[ 192 ](Bei vielen Linux-Distributionen kann das Konvertierungsprogramm nach der Installation
über das Kommando pyuic5 direkt gestartet werden, ohne einen Pfad angeben zu müssen.
)
C:\Python36\Lib\site-packages\PyQt5\pyuic5 -o hauptdialog.py hauptdialog.ui
- Die zweite, an dieser Stelle aufgrund ihrer Einfachheit bevorzugte Möglichkeit ist das Laden einer UI-Datei zur Laufzeit eines PyQt-Programms. Diese Variante wird im Folgenden anhand eines Beispielprogramms erläutert.
Um den vorbereiteten Dialog zu verwenden, erstellen wir die Programmdatei programm.py. Das einfachste Programm, das den Hauptdialog anzeigt und sonst keine weiteren Operationen durchführt, sieht folgendermaßen aus:
import sys
from PyQt5 import QtWidgets, uic
class MeinDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = uic.loadUi("hauptdialog.ui", self)
app = QtWidgets.QApplication(sys.argv)
dialog = MeinDialog()
dialog.show()
sys.exit(app.exec_())
Zunächst werden alle benötigten Module eingebunden. Das sind insbesondere das Modul QtWidgets, in dem alle Widget-Klassen des Qt-Frameworks gekapselt sind, und das Modul uic, mit dessen Hilfe die erstellte UI-Datei gelesen werden kann. Danach wird die Klasse MeinDialog erstellt, die von der Basisklasse aller Qt-Dialoge, QDialog, abgeleitet wird.
Der Konstruktor von MeinDialog ruft neben dem QDialog-Konstruktor die Funktion loadUi auf, um den Hauptdialog aus der UI-Datei hauptdialog.ui zu laden. Die als zweiter Parameter übergebene Instanz, in diesem Fall die MeinDialog-Instanz selbst, fungiert als Eltern-Widget des neuen Dialogs. Die Funktion loadUi gibt das erzeugte Widget zurück.
Im darauffolgenden Code-Block wird eine Instanz der Klasse QApplication erstellt, die den Rahmen einer Anwendung mit grafischer Benutzeroberfläche bereitstellt. Dazu gehört beispielsweise die Main Event Loop, die Hauptschleife der Anwendung. Dem Konstruktor der Klasse QApplication werden die Kommandozeilenparameter sys. argv übergeben. Jede Qt-Anwendung darf immer nur eine einzige QApplication-Instanz haben, unabhängig davon, wie viele Dialoge später angezeigt werden sollen.
Nachdem der Rahmen für die Qt-Anwendung erstellt wurde, kann der Hauptdialog erzeugt werden, indem die Klasse MeinDialog instanziiert wird. Durch die von der Basisklasse QDialog vererbte Methode show wird der Dialog sichtbar. Zu guter Letzt muss die eben angesprochene Main Event Loop durch die Methode exec_ der QApplication-Instanz gestartet werden. Da wir im Moment keine weiteren Operationen durchführen möchten, nachdem der Dialog vom Benutzer geschlossen wurde, geben wir den Rückgabewert von app.exec_ direkt an sys.exit weiter und beenden damit das Beispielprogramm. Das Programm blockiert nach Aufruf von app.exec_ so lange, bis der Benutzer den Hauptdialog schließt.
Dieses einfache Beispielprogramm wird im Folgenden sinnvoll erweitert. So sollen die vom Benutzer eingegebenen Werte ausgelesen und in das neben der Benutzeroberfläche existierende Konsolenfenster geschrieben werden. Anhand der dazu notwendigen Erweiterungen erklären wir im Folgenden das Signal-und-Slot-Konzept von Qt.