PyQt = Python mit Qt

Qt ist ein weit verbreitetes Framework für die Entwicklung von plattformübergreifenden grafischen Benutzeroberflächen (GUIs) . PyQt ist ein Python-Binding für das Qt-Framework und bietet mehr Funktionalitäten als Tkinter.

PyQT muss auf dem System installiert werden. 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. Qt Assistant ist ein Tool zum Lesen der Qt-Hilfe und Qt Linguist ist ein Hilfsmittel zur Lokalisierung von Qt-Anwendungen .

Der QTDesigner kann über die Shell durch $designer aufgerufen werden:

Mit dem Qt Designer erstellen Sie per Drag-and-drop einfache oder komplexe Layouts. Über das GUI-Toolkit PyQt kann man das erstellte Layout dann für sein Python-Programm nutzen. Dabei werden Aussehen und Logik streng getrennt: Das Design wird in einer extra UI-Datei ausgelagert, die Funktionen dafür erstellt man wie gewohnt in der Python-Datei. PyQt-Kentnisse helfen natürlich, allerdings eignet sich der Designer auch gut, um grundlegende Konzepte von PyQt und beziehungsweise Qt zu lernen.

Module und Widgets

Der Hauptunterschied zwischen Modulen und Widgets in PyQt liegt in ihrer Funktion und Struktur:

Widgets:

  • Widgets sind visuelle Elemente der grafischen Benutzeroberfläche (GUI) in PyQt

Sie sind Klassen, die von QWidget abgeleitet sind und repräsentieren UI-Komponenten wie Buttons, Labels, Textfelder etc. Beispiele für Widgets sind QCheckBox, QSlider, QLabel usw. Widgets können in einer Hierarchie angeordnet werden, wobei ein Widget ein Eltern-Widget (parent) haben kann

Module:

  • Module sind Python-Dateien, die Code organisieren und gruppieren

In PyQt werden verschiedene Funktionalitäten in separate Module aufgeteilt, z.B. QtGui, QtWidgets, QtCore

  • Module enthalten Klassen, Funktionen und Variablen, die thematisch zusammengehören.
  • Sie ermöglichen eine strukturierte und modulare Entwicklung von PyQt-Anwendungen.

Zusammengefasst: Widgets sind die visuellen Bausteine der Benutzeroberfläche, während Module die Codeorganisation und -struktur in PyQt-Anwendungen ermöglichen. Widgets werden typischerweise innerhalb von Modulen definiert und verwendet, um GUIs zu erstellen.

Durch den Befehl

pyuic6 -o typeitin.py typeitin.ui 

Wird die QT-Datei in eine Python Klasse umgewandelt.

Ein einfaches Fenster verursacht einen ausführlichen Code:

damit werden die erforderlichen Module importiert:

from PyQt6.QtWidgets import QApplication, QWidget

Für jede PyQt Anwendung muss ein Objekt der Klasse QApplication erstellt werden:

app = QApplication(sys.argv)

Hier wird ein Fenster erzeugt:

w = QWidget()

hier wird w.show genutzt um das Fenster anzuzeigen

w.show()

Was die mainloop Schleife in tkinter ist, ist hier der folgende Befehl:

sys.exit(app.exec_( ) )

Mit diesem wird die Benutzeroberfläche aktiviert.

import sys
from PyQt6.QtWidgets import QApplication, QWidget
if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = QWidget()
    w.resize(300,300)
    w.setWindowTitle("einfaches Fenster mit Python und QT")
    w.show()
    sys.exit(app.exec())

Was Sie sehen, hängt davon ab, auf welcher Plattform Sie dieses Beispiel ausführen. Das Bild unten zeigt das Fenster, wie es unter Windows, macOS und Linux (Ubuntu) angezeigt wird.

Schauen wir uns zunächst einige der gebräuchlichsten PyQt-Widgets an. Der folgende Code erstellt eine Reihe von PyQt-Widgets und fügt sie einem Fensterlayout hinzu, sodass Sie sie zusammen sehen können:

import sys

from PyQt6.QtWidgets import (
    QApplication,
    QCheckBox,
    QComboBox,
    QDateEdit,
    QDateTimeEdit,
    QDial,
    QDoubleSpinBox,
    QFontComboBox,
    QLabel,
    QLCDNumber,
    QLineEdit,
    QMainWindow,
    QProgressBar,
    QPushButton,
    QRadioButton,
    QSlider,
    QSpinBox,
    QTimeEdit,
    QVBoxLayout,
    QWidget,
)

# Subclass QMainWindow to customize your application's main window
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Widgets App")

        layout = QVBoxLayout()
        widgets = [
            QCheckBox,
            QComboBox,
            QDateEdit,
            QDateTimeEdit,
            QDial,
            QDoubleSpinBox,
            QFontComboBox,
            QLCDNumber,
            QLabel,
            QLineEdit,
            QProgressBar,
            QPushButton,
            QRadioButton,
            QSlider,
            QSpinBox,
            QTimeEdit,
        ]

        for w in widgets:
            layout.addWidget(w())

        widget = QWidget()
        widget.setLayout(layout)

        # Set the central widget of the Window. Widget will expand
        # to take up all the space in the window by default.
        self.setCentralWidget(widget)

app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

In Qt finden sich zwei Techniken der ereignisgesteuerten Programmierung: zum einen Events und zum anderen Signale und Slots.

.ui verknüpfen

Die Stylingdatei anrede.ui wird mit der Python Datei verknüpft

import sys
from PyQt6 import QtWidgets, uic

class AnredeDialog(QtWidgets.QDialog):
    def __init__(self):
        super().__init__()
        uic.loadUi("anrede.ui", self)
        self.buttonBox.accepted.connect(self.on_accept)

    def on_accept(self):
        name = self.name.toPlainText()
        if self.frau.isChecked():
            print(f"Sehr geehrte Frau {name}")
        elif self.mann.isChecked():
            print(f"Sehr geehrter Herr {name}")
        else:
            print(f"Sehr geehrte(r) {name}")

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    dialog = AnredeDialog()
    dialog.show()
    sys.exit(app.exec())

Ein Beispiel für eine .ui Datei:
Also als .xml erstellt:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog</class>
 <widget class="QDialog" name="Dialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Dialog</string>
  </property>
  <widget class="QDialogButtonBox" name="buttonBox">
   <property name="geometry">
    <rect>
     <x>30</x>
     <y>240</y>
     <width>341</width>
     <height>32</height>
    </rect>
   </property>
   <property name="orientation">
    <enum>Qt::Horizontal</enum>
   </property>
   <property name="standardButtons">
    <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
   </property>
  </widget>
  <widget class="QTextEdit" name="name">
   <property name="geometry">
    <rect>
     <x>130</x>
     <y>30</y>
     <width>221</width>
     <height>31</height>
    </rect>
   </property>
  </widget>
  <widget class="QLabel" name="label">
   <property name="geometry">
    <rect>
     <x>70</x>
     <y>30</y>
     <width>51</width>
     <height>41</height>
    </rect>
   </property>
   <property name="text">
    <string>Name</string>
   </property>
  </widget>
  <widget class="QRadioButton" name="frau">
   <property name="geometry">
    <rect>
     <x>150</x>
     <y>90</y>
     <width>109</width>
     <height>25</height>
    </rect>
   </property>
   <property name="text">
    <string>weiblich</string>
   </property>
  </widget>
  <widget class="QRadioButton" name="mann">
   <property name="geometry">
    <rect>
     <x>150</x>
     <y>130</y>
     <width>109</width>
     <height>25</height>
    </rect>
   </property>
   <property name="text">
    <string>männlich</string>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>buttonBox</sender>
   <signal>accepted()</signal>
   <receiver>Dialog</receiver>
   <slot>accept()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>248</x>
     <y>254</y>
    </hint>
    <hint type="destinationlabel">
     <x>157</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>buttonBox</sender>
   <signal>rejected()</signal>
   <receiver>Dialog</receiver>
   <slot>reject()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>316</x>
     <y>260</y>
    </hint>
    <hint type="destinationlabel">
     <x>286</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

Ein Label definieren:

label = QLabel(w) wurde festgelegt. In diesem Kontext gibt es kein self, da wir nicht innerhalb einer Klasse sind. Stattdessen verwenden wir w als Elternobjekt für das Label.

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QFrame

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = QWidget()
    w.resize(300, 300)
    w.setWindowTitle("Bist du voll?")
    
    label = QLabel(w)  #
    label.setFrameStyle(QFrame.Shape.Panel | QFrame.Shadow.Sunken)  
    label.setText("Wann bist du geboren?")
    
    w.show()
    sys.exit(app.exec())

Eine Messagbox erstellen:


import sys
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QMessageBox
from PyQt6.QtGui import *
from PyQt6.QtCore import *

def showdialog():
    msg = QMessageBox()
    msg.setWindowTitle("Message")
    msg.setText("This is a message!")
    msg.exec()

def window():
    app = QApplication(sys.argv)
    w = QWidget()
    b = QPushButton(w)
    b.setText("Show message!")

    b.move(50,50)
    b.clicked.connect(showdialog)
    w.setWindowTitle("PyQt Dialog demo")
    w.show()
    sys.exit(app.exec())

if __name__ == '__main__': 
    window()

Ein Eingabefeld erstellen

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QFrame, QVBoxLayout, QLineEdit

class SimpleInput(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # Erstellen eines vertikalen Layouts
        layout = QVBoxLayout()

        # Erstellen und Hinzufügen des Labels
        label = QLabel(self)
        label.setFrameStyle(QFrame.Shape.Panel | QFrame.Shadow.Sunken)
        label.setText("Wann bist du geboren?")
        layout.addWidget(label)

        # Erstellen eines Eingabefeldes
        self.inputField = QLineEdit()
        
        # Hinzufügen des Eingabefeldes zum Layout
        layout.addWidget(self.inputField)

        # Setzen des Layouts für das Fenster
        self.setLayout(layout)

        # Fenster-Eigenschaften
        self.setGeometry(300, 300, 300, 100)
        self.setWindowTitle('Bist du voll?')
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = SimpleInput()
    sys.exit(app.exec())

Einen ok Button erstellen:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QFrame, QVBoxLayout, QLineEdit, QPushButton

class SimpleInput(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # Erstellen eines vertikalen Layouts
        layout = QVBoxLayout()

        # Erstellen und Hinzufügen des Labels
        label = QLabel(self)
        label.setFrameStyle(QFrame.Shape.Panel | QFrame.Shadow.Sunken)
        label.setText("Wann bist du geboren?")
        layout.addWidget(label)

        # Erstellen eines Eingabefeldes
        self.inputField = QLineEdit()
        
        # Hinzufügen des Eingabefeldes zum Layout
        layout.addWidget(self.inputField)

        # Erstellen des OK-Buttons
        ok_button = QPushButton('OK', self)
        ok_button.clicked.connect(self.on_click)

        # Hinzufügen des Buttons zum Layout
        layout.addWidget(ok_button)

        # Setzen des Layouts für das Fenster
        self.setLayout(layout)

        # Fenster-Eigenschaften
        self.setGeometry(300, 300, 300, 150)  # Höhe auf 150 erhöht, um Platz für den Button zu schaffen
        self.setWindowTitle('Bist du voll?')

    def on_click(self):
        print('OK-Button wurde geklickt!')
        # Hier können Sie den eingegebenen Text verarbeiten
        print(f'Eingabe: {self.inputField.text()}')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = SimpleInput()
    ex.show()  # Fenster nach der Initialisierung anzeigen
    sys.exit(app.exec())

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout, QMessageBox

class SimpleInput(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        layout = QVBoxLayout()

        self.label = QLabel("Gib dein Geburtsjahr ein:")
        layout.addWidget(self.label)

        self.inputField = QLineEdit()
        layout.addWidget(self.inputField)

        self.button = QPushButton('Berechnen')
        self.button.clicked.connect(self.on_click)
        layout.addWidget(self.button)

        self.setLayout(layout)
        self.setGeometry(300, 300, 300, 150)
        self.setWindowTitle('Altersrechner')

    def on_click(self):
        try:
            eingabe = self.inputField.text()
            geburtsjahr = int(eingabe)
            alter = 2024 - geburtsjahr
            
            message = f"Du bist {alter} Jahre alt."
            if alter >= 18:
                message += "\nDu bist volljährig."
            else:
                message += "\nDu bist noch nicht volljährig."
            
            QMessageBox.information(self, "Altersberechnung", message)
        except ValueError:
            QMessageBox.warning(self, "Fehler", "Bitte gib ein gültiges Geburtsjahr ein.")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    gebjahr = SimpleInput()
    gebjahr.show()
    sys.exit(app.exec())