PyQt Workshop

Abgeschlossenes Projekt

Projektstatus: 
Workshop hat stattgefunden.

Am 12.03.2015 hat im Ruum42 ein kleiner Workshop zu PyQt 5 (Qt 5 mit Python 3) stattgefunden. Der Fokus lag dabei auf der Erstellung einfacher GUIs mit QWidgets. Falls das Thema auf Interesse stösst kann der Workshop an den darauf folgenden Donnerstagen fortgesetzt werden. Zur Teilnahme benötigst Du:

  • Python 3 (möglichst bereits mit Grundkenntnissen, ich möchte nicht den Workshop von Paul wiederholen ;-) )
  • PyQt 5
  • Einen guten Editor oder eine IDE. Ich empfehle PyCharm.

Wenn Du alles installiert hast kannst Du den folgenden Code mit Python ausführen. Es müsste ein leeres Fenster erscheinen das sich verschieben, in der Grösse verändern und schliessen lässt. Mit dieser Vorlage wird dann auch der Workshop beginnen.

#!/usr/bin/env python3
 
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

 
class Form(QWidget):
    def __init__(self, parent=None):
        super(Form, self).__init__(parent)
 
 
if __name__ == '__main__':
    import sys
 
    app = QApplication(sys.argv)
 
    translator = QTranslator()
    lib_path = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
    translator.load("qt_de.qm", lib_path)
    translator.load("qtbase_de", lib_path)
    app.installTranslator(translator)
 
    window = Form()
    window.show()
 
    sys.exit(app.exec_())

Dies  ist der Code, den wir am Workshop erstellt haben. Die Kommentare mit der Beschreibung folgen noch...

#!/usr/bin/env python3

# Importieren aller Qt Module - man könnte die auch einzeln importieren, gerade
# bei umfangreicheren Projekten würde das aber schnell unübersichtlich. 
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class Form(QWidget):    # Erstellen einer Klasse die von der Basis QWidget erbt. 
    def __init__(self, parent=None):
        super(Form, self).__init__(parent)
        
        # Erstellen eines vertikalen Boxlayots und zuordnen als
        # Hauptlayout dieser Klasse
        layout = QVBoxLayout(self)
        
        # Label mit einem Text erstellen und dem Layout als 
        # erstes Objekt hinzufügen
        self.label = QLabel("Dies ist die Erklärung: 42")
        self.label.setWordWrap(True)
        layout.addWidget(self.label)

        # Eingabefeld erstellen und dem Layout als zweites Objekt hinzufügen.
        self.edit = QLineEdit()
        layout.addWidget(self.edit)

        # Ein horizontales Layout und Zwei Buttons erstellen. Das Layout wird
        # in das Hauptlayout eingefügt, die Buttons in das neue Layout.
        btn_layout = QHBoxLayout()
        layout.addLayout(btn_layout)
        btn1 = QPushButton("&OK")
        btn2 = QPushButton("A&bbrechen")
        btn2.setToolTip("<p>Dieser Button dient zum Beenden des Programms</p>")
        
        # Dadurch bleiben die Buttons am rechten Rand und der leere Bereich
        # links wird mit "Stretch" aufgefüllt.
        btn_layout.addStretch()
        btn_layout.addWidget(btn1)
        btn_layout.addWidget(btn2)

        # Einstellungen aus der letzten Ausführung laden. Wenn keine
        # Einstellungen existieren werden Standarderte eingesetzt.
        self.settings = QSettings("Ruum42", "PyQtWorkshop")
        position = self.settings.value("Position", QPoint(40, 40), type=QPoint)
        window_size = self.settings.value("Size", QSize(10, 10), type=QSize)
        self.move(position)
        self.resize(window_size)

        # Verbinden der Signals und Slots. So werden Aktionen mit
        # Reaktionen verknüpft.
        self.edit.textEdited.connect(self.change_text)
        btn1.clicked.connect(self.change_text)
        btn2.clicked.connect(self.close)

    def change_text(self):
        self.label.setText(self.edit.text())

    # Speichern der Einstellungen beim Beenden des Programms. Diese werden
    # bei der nächsten Ausführung wieder geladen.
    def closeEvent(self, QCloseEvent):
        self.settings.setValue("Position", self.pos())
        self.settings.setValue("Size", self.size())


if __name__ == '__main__':
    import sys
    
    # Erstellen der Eventloop
    app = QApplication(sys.argv)

    # Deutsche Übersetzungen für die Standardtexte in den QWidgets laden.
    # z.B. das Kontextmenü im Eingabefeld. Falls die Einträge trotzdem
    # englisch sind, kann das daran liegen dass das Sprachpaket
    # von Qt nicht installiert ist.
    translator = QTranslator()
    lib_path = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
    translator.load("qt_de.qm", lib_path)
    translator.load("qtbase_de.qm", lib_path)
    app.installTranslator(translator)

    # Ein neues Fenster von unserer Klasse "Form" erstellen und anzeigen.
    window = Form()
    window.show()

    sys.exit(app.exec_())

Hier noch eine kleine Aufgabe, die Du zum aktuellen Stand des Workshops lösen können müsstest:

Erstelle ein Fenster mit 3 Eingabefeldern. In 2 Feldern können Zahlen eingegeben werden die dann über einen Faktor umgerechnet werden. Das dritte Feld enthält den Faktor. Bei jeder Änderung, egal von welchem Wert, soll sofort das Ergebnis aktualisiert werden. (Das Ergebnis soll jeweils im Eingabefeld stehen.) Wenn also der erste Wert 2 ist und der Faktor 1.2, so soll der zweite Wert 2.4 sein. Wird der 2. Wert editiert auf z.B. 3.6, so ändert sich der erste Wert auf 3. Bei Änderung des Faktors wird entsprechend der 2. Wert angepasst.

Und hier die Umsetzung dieser Übung wie wir sie am 19.03.2015 gemacht haben:

#!/usr/bin/env python3

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class Form(QWidget):
    def __init__(self, parent=None):
        super(Form, self).__init__(parent)
      
        # Titel des Fensters festlegen
        self.setWindowTitle("Rechner")

        # Transparenz... Eher eine Spielerei, daher auskommentiert.
        # self.setWindowOpacity(0.5)

        # Einstellungen laden
        self.settings = QSettings("Ruum42", "Rechner")
        position = self.settings.value("Position", QPoint(40, 40), type=QPoint)
        window_size = self.settings.value("Size", QSize(10, 10), type=QSize)
        self.move(position)
        self.resize(window_size)

        # Layout und GUI- Elemente definieren                
        layout = QGridLayout(self)
        lbl_wert1 = QLabel("Wert 1:")
        lbl_wert2 = QLabel("Wert 2:")
        lbl_faktor = QLabel("Faktor :")
        self.edt_wert1 = QLineEdit()
        self.edt_wert2 = QLineEdit()
        self.edt_faktor = QLineEdit()
        self.btn_quit = QPushButton("B&eenden")
        layout.addWidget(lbl_wert1, 0, 0)
        layout.addWidget(lbl_wert2, 1, 0)
        layout.addWidget(lbl_faktor, 2, 0)
        layout.addWidget(self.edt_wert1, 0, 1)
        layout.addWidget(self.edt_wert2, 1, 1)
        layout.addWidget(self.edt_faktor, 2, 1)
        layout.addWidget(self.btn_quit, 3, 0, 1, 2)

        # Signals und Slos verbinden
        self.btn_quit.clicked.connect(self.close)
        self.edt_wert1.textEdited.connect(self.calc_wert2)
        self.edt_wert2.textEdited.connect(self.calc_wert1)
        self.edt_faktor.textEdited.connect(self.calc_wert2)

    # rechnen...
    def calc_wert2(self):
        self.edt_wert2.clear()
        zahl1 = float(self.edt_wert1.text())
        faktor = float(self.edt_faktor.text())
        zahl2 = zahl1 * faktor
        self.edt_wert2.setText(str(zahl2))

    def calc_wert1(self):
        self.edt_wert1.clear()
        zahl2 = float(self.edt_wert2.text())
        faktor = float(self.edt_faktor.text())
        zahl1 = zahl2 / faktor
        self.edt_wert1.setText(str(zahl1))

    # Ein Beispiel für eine Fehlermeldung. Wird im Code nicht mehr verwendet.
    # Zu Dokumentationszwecken lasse ich sie aber drin.
    def fehler(self):
        QMessageBox.critical(self, "Warnung", "Kein Weltraum links vom Gerät")

    # Einstellungen beim Beenden speichern
    def closeEvent(self, QCloseEvent):
        self.settings.setValue("Position", self.pos())
        self.settings.setValue("Size", self.size())

# Nur ausführen wenn direkt aufgerufen.
if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)

    translator = QTranslator()
    lib_path = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
    translator.load("qt_de.qm", lib_path)
    translator.load("qtbase_de", lib_path)
    app.installTranslator(translator)

    window = Form()
    window.show()

    sys.exit(app.exec_())

Der Workshop ist damit abgeschlossen. Selbstverständlich bin ich jederzeit gerne bereit, euch bei der Umsetzung individueller Projekte mit PyQt zu unterstützen. Sprecht mich dazu bitte eifach im Ruum42 darauf an.

Kommentare

Bild des Benutzers stof999