PyQt5 Handledning med exempel: Designa GUI med PyQt in Python

Vad är PyQt?

PyQt är en python-bindning av widget-verktygssatsen Qt med öppen källkod, som också fungerar som ett ramverk för applikationsutveckling över flera plattformar. Qt är en populär C++ ramverk för att skriva GUI-applikationer för alla större stationära, mobila och inbyggda plattformar (stödjer Linux, Windows, Mac OS, Android, iOS, Raspberry Pi och mer).

PyQt är en fri programvara utvecklad och underhållen av Riverbank Computing, ett företag baserat i England, medan Qt är utvecklat av ett finskt företag som heter The Qt Company.

Funktioner i PyQT

Här är viktiga funktioner i PyQt:

Lär dig PyQt som består av mer än sexhundra klasser som täcker en rad funktioner som t.ex

  • Grafiska användargränssnitt
  • SQL Databaser
  • Webbverktygssatser
  • XML-bearbetning
  • nätverk

Dessa funktioner kan kombineras för att skapa avancerade användargränssnitt såväl som fristående applikationer. Många stora företag inom alla branscher använder Qt. Några exempel är LG, Mercedes, AMD, Panasonic, Harman, etc.

PyQt-versioner

PyQt finns i två utgåvor, PyQt4 och PyQt5. PyQt4 tillhandahåller limkod för att binda 4.x- och 5.x-versioner av Qt-ramverket medan PyQt5 endast tillhandahåller en bindning för 5.x-versionerna. Som ett resultat är PyQt5 inte bakåtkompatibel med de föråldrade modulerna i den äldre versionen. I denna Qt GUI-handledning kommer PyQt5 att användas för att demonstrera exempel. Förutom dessa två versioner,

Riverbank Computing tillhandahåller också PyQt3D – pythonbindningarna för Qt3D-ramverket. Qt3D är ett applikationsramverk som används för att skapa realtidssimuleringssystem med 2D/3D-rendering.

Hur man installerar PyQt5

I denna PyQt5-handledning kommer vi att se de två sätten att installera PyQt:

  • Använder hjulfiler
  • Bygga och installera från källan

Qt (uttalas söt) är ett komplext system, och PyQt-kodbasen innehåller kompilerade C++ och Python kod under huven. Som ett resultat är det en komplicerad process att bygga och installera den från källan jämfört med andra pythonbibliotek. Du kan dock enkelt installera PyQt5 med hjälp av hjul.

Montering med hjul

Hjul är den nya standarden Python förpacknings- och distributionsformat. Ett hjul är helt enkelt ett ZIP-arkiv med ett speciellt namn och .WHL filtillägg. Hjul kan installeras med pip (Pythons pakethanterare), som ingår som standard i de senaste versionerna av Python.

Så, om du har Python 3.4 eller senare installerat, du har redan pip. Om du däremot använder en äldre version av Python, måste du ladda ner och installera pip innan du går vidare. Du kan söka efter instruktioner för det på denna länk: https://pypi.org/project/pip/.

För att installera PyQt5,

Steg 1) Öppna kommandotolken.
Öppna kommandotolken eller PowerShell i din Windows maskin.

installera PyQt5

Steg 2) Skriv in följande.

 pip install PyQt5

Steg 3) Lyckad installation.
Det här steget i denna PyQt5-handledning kommer att ladda ner PyQt5 whl-paketet (ca 50 MB) och installera det på ditt system.

installera PyQt5

Alternativt kan du också ladda ner en Windows binär för versionen av python installerad på din dator.

När det är klart, fortsätt till nästa avsnitt i denna PyQt5-handledning för att skriva din första GUI-app.

Grundläggande PyQt Concepts och program

Nu när du framgångsrikt har installerat PyQt5 i din dator är du redo att skriva Python GUI-designapplikationer.

Låt oss börja med en enkel app i denna PyQt5-handledning som visar ett tomt fönster på din skärm.

Sätt igång din python IDLE och skriv in följande:

Program 1

import sys
from PyQt5.QtWidgets import QApplication, QWidget
if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = QWidget()
    w.resize(300,300)
    w.setWindowTitle("Guru99")
    w.show()
    sys.exit(app.exec_())

Spara det som app.py (namnet spelar ingen roll) och tryck på F5 för att köra programmet. Alternativt, dubbelklicka bara på din sparade fil för att starta programmet. Om du har gjort allt rätt kommer ett nytt fönster att öppnas med titeln Guru99 som visas nedan.

Grundläggande PyQt Concepts

Bra! Det fungerar. Det är inte mycket, men det räcker för att förstå grunderna. Nu i denna PyQt-handledning, låt oss se i detalj vad var och en av raderna i ditt program gör.

from PyQt5.QtWidgets import QApplication, QWidget

Denna sats importerar alla moduler du behöver för att skapa ett GUI till det aktuella namnområdet. QtWidgets-modulen innehåller alla större widgets som du kommer att använda i detta Python Qt handledning.

app = QApplication(sys.argv)

Här skapar du ett objekt av klassen QApplication. Detta steg är en nödvändighet för PyQt5; varje UI-app måste skapa en instans av QApplication, som en slags ingångspunkt till appen. Om du inte skapar det kommer fel att visas.

sys.argv är listan över kommandoradsparametrar som du kan skicka till programmet när du startar det genom skalet eller när du automatiserar gränssnittet.

I detta PyQt5-exempel skickade du inga argument till QApplications. Därför kan du även ersätta den med koden nedan och inte ens behöva importera sys-modulen.

app = QApplication([])
w = QWidget()

Därefter gör vi ett objekt av klassen QWidget. QWidget är basklassen för alla UI-objekt i Qt, och praktiskt taget allt du ser i en app är en widget. Det inkluderar dialoger, texter, knappar, staplar och så vidare. Funktionen som gör att du kan designa komplexa användargränssnitt är att widgetarna kan kapslas, dvs du kan ha en widget inuti en widget, som finns i ännu en widget. Du kommer att se detta i aktion i nästa avsnitt.

w.resize(300,300)

Resize-metoden för QWidget-klassen låter dig ställa in måtten på vilken widget som helst. I det här fallet har du ändrat storleken på fönstret till 300px med 300px.

Här bör du komma ihåg att widgets kan kapslas ihop, den yttersta widgeten (dvs. widgeten utan förälder) kallas ett fönster.

w.setWindowTitle("Guru99")

Metoden setWindowTitle() låter dig skicka en sträng som ett argument som kommer att ställa in titeln på fönstret till den sträng du skickar. I PyQt5-exemplet kommer titelraden att visa Guru99.

w.show()

show() visar helt enkelt widgeten på skärmen.

sys.exit(app.exec_())

Metoden app.exec_() startar Qt/C++ händelseslinga. Som ni vet är PyQt till stor del inskrivet C++ och använder händelseloopmekanismen för att implementera parallell exekvering. app.exec_() överför kontrollen till Qt som kommer att avsluta applikationen endast när användaren stänger den från GUI. Det är därför ctrl+c inte kommer att avsluta programmet som i andra pythonprogram. Eftersom Qt har kontroll över appen, bearbetas inte python-händelser om vi inte ställer in dem i applikationen. Observera också att exec-metoden har ett understreck i sitt namn; detta beror på att exec() redan var ett nyckelord i python och understrecket löser namnkonflikt.

Bortom tomma fönster

I föregående avsnitt såg du hur man gör en grundläggande widget i Qt. Det är nu dags att skapa några mer involverade gränssnitt som användarna verkligen kan interagera med. Återigen, elda upp din IDLE och skriv följande.

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QMessageBox

def dialog():
    mbox = QMessageBox()

    mbox.setText("Your allegiance has been noted")
    mbox.setDetailedText("You are now a disciple and subject of the all-knowing Guru")
    mbox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
            
    mbox.exec_()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = QWidget()
    w.resize(300,300)
    w.setWindowTitle("Guru99")
    
    label = QLabel(w)
    label.setText("Behold the Guru, Guru99")
    label.move(100,130)
    label.show()

    btn = QPushButton(w)
    btn.setText('Beheld')
    btn.move(110,150)
    btn.show()
    btn.clicked.connect(dialog)

    
    w.show()
    sys.exit(app.exec_())

Spara filen som appone.py eller något du vill och tryck på F5 för att köra programmet. Om du inte har gjort några misstag, IDLE kommer att öppna ett nytt fönster med lite text och en knapp som visas nedan.

Bortom tomt Windows

  1. När du klickar på knappen i det första fönstret öppnas en ny meddelanderuta med texten du skrivit.
  2. Du kan nu klicka på knappen Dölj detaljer/Visa detaljer för att växla synligheten för ytterligare text.

Som du kan se, eftersom vi inte hade ställt in någon fönstertitel i meddelanderutan, tillhandahölls en standardtitel av python själv.

Nu när det fungerar låt oss ta en titt på den extra koden som du har lagt till i det tidigare PyQt5-exemplet.

from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QMessageBox

Detta importerar några fler widgets som du har använt i PyQt5-exemplen, nämligen QLabel, QPushButton och QMessageBox.

def dialog():
    mbox = QMessageBox()

    mbox.setText("Your allegiance has been noted")
    mbox.setDetailedText("You are now a disciple and subject of the all-knowing Guru")
    mbox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
            
    mbox.exec_()

Här har du definierat en metod med namnet dialog som skapar en meddelandebox-widget och ställer in lite text till knapparna och andra fält.

Dialogmetoden anropas från programmets huvudblock när en knapp trycks in i en specifik widget (i detta fall btn-tryckknappen). Klickhändelsen som utlöses på den knappen gör att den här funktionen körs. En sådan funktion kallas slot i Qt, och du kommer att lära dig mer om signaler och spelautomater i de kommande styckena.

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = QWidget()
    w.resize(300,300)
    w.setWindowTitle("Guru99")

Detta är huvuddelen av appen och som i föregående exempel börjar du med att skapa en instans av QApplication följt av en enkel widget, alltså en instans av QWidget.

label = QLabel(w)
    btn = QPushButton(w)

Du har lagt till två nya widgets i denna applikation: QLabel och QPushButton. QLabel används för att skriva ut icke-redigerbar text eller platshållare inuti en widget, medan QPushButton används för att skapa en klickbar knapp.

Det kritiska att lägga märke till här är att när du skapar etikett- och btn-objekten skickar du fönsterobjektet (w) till konstruktörerna av QLabel och QPushButton. Så här fungerar kapsling i PyQt5. För att skapa en widget i en annan widget skickar du referensen för den överordnade widgeten till barnets konstruktor.

label.move(100,130)
btn.move(110,150)

move() används för att ställa in positionen för en widget i förhållande till dess överordnade widget. I det första fallet kommer etiketten att flyttas 100px från vänster och 130px från toppen av fönstret.

På samma sätt kommer knappen att placeras 110px från vänster och 150px från toppen av fönstret. Detta exempel är ett grovt sätt att uppnå layouter och används vanligtvis inte i produktionen; den ingår bara här i lärande syfte. Qt stöder olika layouter som du kommer att se i detalj i de kommande avsnitten av denna PyQt-handledning.

btn.clicked.connect(dialog)

Slutligen är detta ett exempel på signaler och luckor i Qt. I GUI-baserade applikationer exekveras funktioner baserat på de åtgärder som utförs av användaren, som att hålla muspekaren över ett element eller klicka på en knapp. Dessa åtgärder kallas händelser. Kom ihåg att metoden app.exec_() överför kontrollen till Qt händelse-slinga. Detta är vad händelseslingan är till för: att lyssna efter händelser och utföra åtgärder som svar.

Närhelst en händelse inträffar, som att en användare klickar på en knapp, höjer motsvarande Qt-widget en signal. Dessa signaler kan kopplas till python-funktioner (som dialogfunktionen i detta exempel) så att funktionen exekveras när en signal triggas. Dessa funktioner kallas spelautomater på Qt-språk.

Därefter är den grundläggande syntaxen för att trigga en slotfunktion som svar på signalen från en händelse som följer

 widget.signal.connect(slot)

Vilket betyder att när en signal utlöses av en widget, den anslutna slits funktionen kommer att köras. Sammanfattningsvis används signaler och slots av Qt för att kommunicera mellan objekt och underlätta återanvändbarhet och interaktivitet av komponenter.

Nu när du vet hur man kapslar widgets och implementerar interaktioner med hjälp av signaler och slots, här är en lista med användbara widgets och andra klasser som du kan använda i dina PyQt-appar.

Komponenter och widgets

Det finns ett stort antal widgets tillgängliga i PyQt för att skapa GUI-appar. Men med PyQt5 har det skett en omblandning av klasser till olika moduler och revisioner i licenserna.

Därför är det avgörande att ha en överblick över strukturen i PyQt5. I det här avsnittet kommer du att se hur PyQt5 är organiserat internt och lära dig om de olika modulerna, biblioteken och API-klasserna som tillhandahålls av PyQt5.

PyQt5 Katalogstruktur

PyQt5 Katalogstruktur

Dessa är de grundläggande modulerna som används av Pythons Qt-bindning, specifikt PyQt5.

  • Qt: Den kombinerar alla klasser/moduler som nämns nedan till en enda modul. Det ökar avsevärt minnet som används av applikationen. Det är dock enklare att hantera ramverket genom att bara importera en modul.
  • QtCore: Innehåller de icke-grafiska kärnklasserna som används av andra moduler. Det är här Qt-händelseloopen, signaler och slot-anslutning etc. implementeras.
  • QtWidgets: Innehåller de flesta widgets som finns tillgängliga i Pyqt5.
  • QtGui: Innehåller GUI-komponenter och utökar QtCore-modulen.
  • QtNetwork: Innehåller klasser som används för att implementera nätverksprogrammering genom Qt. Den stöder TCP-servrar, TCP-sockets, UDP-sockets, SSL-hantering, nätverkssessioner och DNS-sökningar.
  • QtMultimedia ger multimediafunktionalitet på låg nivå.
  • QtSql: implementerar databasintegration för SQL-databaser. Stöder ODBC, MySQL, Oracle, SQLiteoch PostgreSQL.

PyQt5-widgets

Här är en lista över de mest använda widgetarna i PyQt5

  • QLineEdit: Detta är ett inmatningsfält som tillåter en textrad att skrivas in av användaren.
    line = QLineEdit()
  • QRadioButton: Detta är ett inmatningsfält med en valbar knapp, liknande radioknapparna i html.
    rad = QRadioButton("button title")
    rad.setChecked(True)  #to select the button by default.
  • QComboBox: Den används för att visa en rullgardinsmeny med en lista över valbara objekt.
    drop = QComboBox(w)
    drop.addItems(["item one", "item two", "item three"])
  • QCheckBox: Visar en valbar fyrkantig ruta framför etiketten som är markerad om den är markerad, liknande alternativknappar.
    check = QCheckBox("button title")
  • QMenuBar: den visar en horisontell menyrad överst i ett fönster. Du kan bara lägga till objekt av klassen QMenu till denna stapel. Dessa QMenu-objekt kan dessutom innehålla strängar, QAction-objekt eller andra QMenu-objekt.
  • QToolBar: Det är en horisontell stapel eller ruta som kan flyttas inom fönstret. Den kan innehålla knappar och andra widgets.
  • QTab: det används för att dela upp innehållet i ett fönster i flera sidor som kan nås via olika flikar ovanpå widgeten. Den består av två sektioner: flikfältet och fliksidan.
  • QScrollBar: Den används för att skapa rullningslister som låter användaren rulla upp och ner i ett fönster. Den består av ett rörligt skjutreglage, ett skjutreglage och två knappar för att rulla skjutreglaget uppåt eller nedåt.
    scroll = QScrollBar()
  • QSplitter: Splittrar används för att separera innehållet i ett fönster så att widgetarna grupperas korrekt och inte verkar röriga. QSplitter är en av de primära layouthanterarna som finns i PyQt5 och används för att dela upp innehållet både horisontellt och vertikalt.
  • QDock: En dockningswidget är ett underfönster med två egenskaper:
  • Den kan flyttas inom huvudfönstret och
  • Den kan dockas utanför föräldrafönstret till en annan plats på skärmen.

Layouter och teman

I de tidigare PyQt5-exemplen har du bara använt metoderna move() och resize() för att ställa in positionerna för widgets i ditt GUI.

PyQt har dock en robust layouthanteringsmotor som kan användas för att skapa avancerade användargränssnitt för applikationer. I det här avsnittet kommer du att lära dig om två viktiga klasser som används i Qt för att skapa och hantera layouter.

  1. QBoxLayout
  2. QGridLayout

QBoxLayout

QBoxLayout används för att justera layoutens underordnade widgets i en horisontell eller vertikal rad. De två intresseklasserna som ärver från QBoxLayouten är:

  • QHBoxLayout: används för att rada de underordnade widgetarna horisontellt.
  • QVBoxLayout: används för att rada de underordnade widgetarna vertikalt.

Till exempel är det så här tre knappar är i linje med QHBoxLayouten kommer att se ut.

QBoxLayout

import sys
from PyQt5.QtWidgets import *

if __name__ == "__main__":

    app = QApplication([])
    w = QWidget()
    w.setWindowTitle("Musketeers")

    btn1 = QPushButton("Athos")
    btn2 = QPushButton("Porthos")
    btn3 = QPushButton("Aramis")

    hbox = QHBoxLayout(w)

    hbox.addWidget(btn1)
    hbox.addWidget(btn2)
    hbox.addWidget(btn3)

    w.show()

    sys.exit(app.exec_())

Och så här kommer de att se ut i QVBoxLayout.

QBoxLayout

import sys
from PyQt5.QtWidgets import *

if __name__ == "__main__":

    app = QApplication([])
    w = QWidget()
    w.setWindowTitle("Musketeers")

    btn1 = QPushButton("Athos")
    btn2 = QPushButton("Porthos")
    btn3 = QPushButton("Aramis")

    vb = QVBoxLayout(w)

    vb.addWidget(btn1)
    vb.addWidget(btn2)
    vb.addWidget(btn3)

    w.show()

    sys.exit(app.exec_())

Den enda funktionen som behöver någon förklaring vid det här laget är metoden addWidget(). Den används för att infoga widgets i HBox eller VBox layout. Det används också i andra layouter där det tar ett annat antal parametrar som du kommer att se i nästa avsnitt. Widgetarna kommer att visas i layouten i den ordning som du infogar dem.

QGridLayout

QGridLayout används för att skapa gränssnitt där widgetarna är upplagda i form av ett rutnät (som en matris eller 2D-array). För att infoga element i en rutnätslayout kan du använda matrisrepresentationen för att definiera antalet rader och kolumner i rutnätet samt positionen för dessa element.

Till exempel, för att skapa ett 3*3 rutnät (dvs ett rutnät med tre rader och tre kolumner), skriver du följande kod:

Import sys
from PyQt5.QtWidgets import *

if __name__ == "__main__":
    app = QApplication([])

    w = QWidget()

    grid = QGridLayout(w)

    for i in range(3):
        for j in range(3):
            grid.addWidget(QPushButton("Button"),i,j)


    w.show()
    sys.exit(app.exec_())

Detta kommer att vara utgången:

QGridLayout

Metoden addWidget() I rutnätslayouten tar dessa argument:

  • Widgetobjektet som du vill lägga till i rutnätet
  • Objektets x-koordinat
  • Objektets y-koordinat
  • Radintervallet (standard =0)
  • Kolomfånget (standard=0)

För att förstå det bättre kan du infoga varje widget manuellt som visas nedan

import sys
from PyQt5.QtWidgets import *

if __name__ == "__main__":
    app = QApplication([])

    w = QWidget()

    grid = QGridLayout(w)
    grid.addWidget(QPushButton("Button one"),0,0)
    grid.addWidget(QPushButton("Button two"),0,1)
    grid.addWidget(QPushButton("Button three"),1,0)
    grid.addWidget(QPushButton("Button four"),1,1)


    w.show()
    sys.exit(app.exec_())

Så här kommer rutnätet att se ut:

QGridLayout

Du kan också skicka parametrarna rowspan och colspan till addWidget() för att spänna över mer än en rad eller kolumn.

Till exempel,

grid.addWidget(QPushButton("Button five"),2,0,1,0)

Detta skapar en knapp som sträcker sig över båda kolumnerna.

QGridLayout

teman

PyQt5 kommer med några inbyggda teman som du kan använda i dina appar. De setStyle() metod som anropas på QApplication-instansen används för att ställa in ett särskilt tema för din applikation.

Om du till exempel lägger till följande kodrad kommer temat för din applikation att ändras från standard till Fusion

app.setStyle("Fusion")

Så här kommer det föregående exemplet att se ut i Fusion Theme

teman

En annan användbar funktion för att temaisera dina appar är metoden setPalette(). Här är koden för att ändra färgen på olika widgets med setPalette().

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPalette

if __name__ == "__main__":
    app = QApplication([])
    app.setStyle("Fusion")
    
    qp = QPalette()
    qp.setColor(QPalette.ButtonText, Qt.black)
    qp.setColor(QPalette.Window, Qt.black)
    qp.setColor(QPalette.Button, Qt.gray)
    app.setPalette(qp)

    w = QWidget()

    grid = QGridLayout(w)
    grid.addWidget(QPushButton("Button one"),0,0)
    grid.addWidget(QPushButton("Button two"),0,1)
    grid.addWidget(QPushButton("Button three"),1,0)
    grid.addWidget(QPushButton("Button four"),1,1)


    w.show()
    sys.exit(app.exec_())

Här är resultatet.

teman

För att använda metoden setPalette() måste du först definiera en palett. Detta görs genom att skapa ett objekt av klassen QPalette.

 qp = QPalette()

Lägg märke till att QPalette-klassen tillhör QtGui-modulen och du måste importera den för att detta ska fungera. När du har skapat QPalette-objektet använder du metoden setColor() för att skicka namnet på en widget vars färg du vill ändra och färgen du vill ska ställas in.

 qp.setColor(QPalette.Window, Qt.black)

Detta kommer att ändra färgen på fönstret till svart. När du har definierat ditt färgschema, använd funktionen setPalette() för att tillämpa paletten på din applikation.

app.setPalette(qp)

Det är allt du behöver göra om du vill skapa några grundläggande teman för din app. PyQt låter dig också använda stilmallar för att definiera utseendet på dina widgets. Om du är bekant med CSS kan du enkelt definiera avancerade stilar för din app med hjälp av Qt Style Sheets.

Sammanfattning

  • PyQt är pytonbindningen för C++ UI-ramverk, Qt.
  • PyQt4 och PyQt5 är de två huvudversionerna utvecklade av Riverbank Computing.
  • Huvudmodulerna i PyQt-ramverket är:
    1. Qt
    2. QtCore
    3. QtWidgets
    4. QtGui
    5. QtSql
    6. QtNetwork
  • PyQt stöder olika widgets som:
    1. Knappar
    2. Textetiketter
    3. Textfält
    4. Radioknappar och kryssrutor
    5. Verktygsfält och menyfält
    6. Webbkit
    7. Flikar
    8. Docks
  • I PyQt implementeras interaktivitet med hjälp av signaler och slitsar.
  • An händelse är en åtgärd som utförs av en användare i GUI (som att klicka på en knapp).
  • A signal höjs av motsvarande widget när en händelse inträffar på den.
  • A slits är en funktion som är kopplad till signalen och körs när signalen höjs.
  • PyQt har en robust layoutmotor och stöder avancerad layoutdesign och hantering. Dessa är två ofta använda layoutscheman i PyQt:
    1. Box Layout
    2. Grid layout
  • PyQt-designern låter dig skapa anpassade teman för GUI-applikationer och har inbyggt stöd för stilmallar.
  • qtcreator Python kan användas för att skapa användargränssnitt såväl som fristående applikationer.