Python >> Tutoriel Python >  >> Python GUI >> PyQt GUI

Travailler avec le framework PyQT de Python

Introduction

Dans ce guide, nous verrons comment utiliser le framework PyQT de Python pour développer une interface utilisateur graphique (GUI) pour une application de bureau en Python.

Les alternatives Python populaires pour développer une interface graphique incluent Tkinter, Kivy, PySimpleGUI, et wxPython .

Remarque : Au moment d'écrire ce tutoriel, PyQt6 est la version la plus récente et la plus avancée du framework PyQT de Python, ainsi que la version que nous utiliserons.

Nous allons passer par le processus d'installation et nous familiariser avec les éléments clés de PyQT, avant de passer aux gestionnaires de mise en page , Widgets , Signaux et créneaux ainsi que comment Style Widgets , ainsi qu'un aperçu des fichiers d'interface utilisateur et de la création d'interfaces utilisateur via une interface intuitive par glisser-déposer, que nous pouvons ensuite exporter dans des scripts Python exécutables :

  • Installation

  • Présentation de PyQt

  • Gestionnaires de mise en page

  • Widgets

    • Libellés
    • Boutons
    • Modifications de ligne
    • Zones combinées
    • Boutons radio
    • Afficher des données à l'aide d'un widget de tableau
    • Afficher des données à l'aide d'un widget d'arborescence
  • Signaux et créneaux

  • Styliser les applications Widgets

  • Fichiers d'interface utilisateur

    • qtDesigner
    • Conversion des fichiers d'interface utilisateur en Python
  • Conclusion

Installation

Pour utiliser le framework PyQt, nous devons d'abord l'installer à l'aide du gestionnaire de packages pip.

Si pip est installé sur votre système, exécutons la commande suivante pour installer la dernière version de PyQt :

$ pip install pyqt6

Devrait pip install pyqt6 échoue, vous pouvez vérifier les modifications d'installation ici.

Introduction à PyQt

PyQt est une boîte à outils issue de la bibliothèque Qt et du langage de programmation Python. Comme PyQt est l'un des frameworks GUI les plus couramment utilisés pour Python, il existe à la fois des tonnes de documentation bien écrite et une grande communauté.

L'une des classes de base de PyQt est le QWidget classe - l'implémentation d'un Widget . Les widgets sont des composants GUI et les blocs de construction de base des interfaces utilisateur. Un widget peut être une étiquette, un bouton, un menu, une liste déroulante, un scroller, une barre d'outils, une boîte de dialogue de fichier, etc...

Il y en a beaucoup Les widgets, et s'y habituer prend du temps. Nous allons passer en revue les widgets les plus couramment utilisés qui seront pour la plupart présents dans presque toutes les applications PyQt.

L'ordre relatif de ces Widgets sur le cadre d'une application est dicté et géré par un Layout Manager . Nous examinerons également les gestionnaires de mise en page disponibles et leur influence sur le positionnement des composants de l'interface graphique.

Le point d'entrée de chaque application PyQt est le QApplication classe, qui représente l'application elle-même. Il gère toute l'initialisation et le "canevas" sur lequel nous dessinons.

Remarque : Il n'y a toujours qu'un seul QApplication instance, quel que soit le nombre de fenêtres ou de boîtes modales dans votre application.

Faisons un saut et initialisons une application PyQt, et initialisons une fenêtre avec un canevas vide :

import sys
from PyQt6.QtWidgets import QApplication, QWidget
app = QApplication(sys.argv)
root = QWidget()
root.setWindowTitle('A Simple PyQt6 App')
root.setGeometry(100, 100, 280, 80)
root.show()
sys.exit(app.exec())

L'exécution de ce code initialise une application simple :

Passons en revue cette initialisation ligne par ligne.

Tout d'abord, nous importons le Python intégré sys module qui nous fournit des fonctions pour manipuler l'Python Runtime Environment . Dans notre cas, nous utiliserons ce module pour gérer l'état de sortie de l'application - lorsqu'un utilisateur appuie sur le "X" bouton :

import sys

Ensuite, nous pouvons importer QApplication (la base) et QWidget (les composants GUI) du PyQt6.QtWidgets modules :

from PyQt6.QtWidgets import QApplication, QWidget

Ensuite, cette ligne est une exigence de QT. Il initialisera PyQT. Le sys.argv contient une liste de tous les arguments de ligne de commande passés à l'application. Chaque application graphique que vous créez doit avoir exactement une instance de QApplication.

Maintenant, depuis QApplication est responsable de l'initialisation de la plupart des éléments impliqués dans le développement d'applications PyQt, nous voudrons d'abord l'instancier. Le constructeur accepte un sys.argv argument car vous pouvez également passer des arguments de ligne de commande :

app = QApplication(sys.argv)

Maintenant, le QApplication lui-même n'a pas de fenêtres. Exécuter l'application sans fenêtre produira un résultat invisible pour nous. Pour réellement introduire une fenêtre dans le mix, nous allons créer un Root Widget , également connu sous le nom de Widget de fenêtre . Dans tous les cas, il représente le Widget le plus bas auquel nous ajouterons d'autres composants :

root = QWidget()

Définissons un titre de fenêtre personnalisé en utilisant setWindowTitle() :

root.setWindowTitle('A Simple PyQt6 App')

Le setGeometry() la méthode accepte 4 arguments :x_coordinate , y_coordinate , width &height . Le x_coordinate et y_coordinate définir le point d'origine de la Fenêtre lorsqu'il est affiché :

root.setGeometry(100, 100, 280, 80)

Maintenant, pour afficher l'interface graphique créée à l'écran, nous appelons le show() méthode sur le root :

root.show()

Enfin, nous exécutons l'application via app.exec() , et exécutez la boucle principale de l'application jusqu'à l'utilisateur le ferme :

sys.exit(app.exec())

Gestionnaires de mise en page

Gestionnaires de mise en page de PyQt fournissez-nous un moyen productif d'organiser les widgets PyQt sur une interface graphique. Mieux nous présentons nos widgets, plus notre application graphique peut être soignée et professionnelle. Avoir des espaces énormes et gênants entre les boutons sans beaucoup d'utilisation de l'espace n'est pas très convivial. Il en va de même dans l'autre sens :si nous plaçons les boutons trop près, ils deviendront inconfortablement faciles à mal cliquer.

Les classes PyQt Layout Manager les plus populaires sont :

  1. QVBoxLayout organise les widgets verticalement.
  2. QHBoxLayout organise les widgets horizontalement.
  3. QGridLayout organise les Widgets dans une grille.
  4. QFormLayout organise les widgets sur deux colonnes.

Lors de la création d'applications graphiques avec PyQt, vous utiliserez souvent plus d'un des quatre gestionnaires de disposition à usage général, même dans la même application, pour différents types de fenêtres.

Tirons parti de l'exemple précédent et mettons-le à niveau en ajoutant plusieurs widgets tels que QPushButton s et de les gérer via un gestionnaire de mise en page.

1. QVBoxLayout

Un gestionnaire de mise en page de boîte (les deux QVBox ou QHBox ) utilise tout l'espace qu'il obtient de sa mise en page parente ou Widget et le divise en plusieurs cases.

QVBoxLayout nous permet d'organiser nos Widgets verticalement. La mise en page ajoute les Widgets à elle-même de haut en bas, de manière séquentielle. Ainsi, le premier Widget ajouté dans votre code sera le Widget le plus haut et le dernier Widget ajouté dans votre code sera le plus bas dans la mise en page.

Ajoutons plusieurs boutons à notre application, via un QVBoxLayout :

#!/usr/bin/python
# Import all needed modules
import sys
from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget

# Create the Qt Application
app = QApplication(sys.argv)

# Create the root Widget/Window
window = QWidget()

# Create the Vertical Box Layout Manager, setting `window` as parent by passing it in the constructor.
layout = QVBoxLayout(window)

# Create and add the QPushButton Widgets to the `layout`
layout.addWidget(QPushButton('One'))
layout.addWidget(QPushButton('Two'))
layout.addWidget(QPushButton('Three'))
layout.addWidget(QPushButton('Four'))
layout.addWidget(QPushButton('Five'))

# Show the parent Widget
window.show()

# Run the main Qt loop and allow safe exiting
sys.exit(app.exec())

Une fois que nous avons exécuté ce code, nous pouvons voir la fenêtre suivante sur notre écran :

Cette fenêtre contient 5 boutons disposés verticalement, de haut en bas. Rien ne se passe lorsque nous cliquons dessus car nous n'avons pas encore ajouté de logique pour eux.

2. QHBoxLayout

QHBoxLayout est une mise en page de boîte qui nous permet d'organiser nos Widgets horizontalement. La mise en page ajoute les Widgets à elle-même de gauche à droite. Ainsi, le premier Widget ajouté dans votre code sera le Widget le plus à gauche et le dernier Widget ajouté dans votre code sera le Widget le plus à droite dans la mise en page.

Remplaçons la case verticale par une case horizontale :

#!/usr/bin/python
# Import all needed modules
import sys
from PyQt6.QtWidgets import QApplication, QPushButton, QHBoxLayout, QWidget

# Create the Qt Application
app = QApplication(sys.argv)

# Create the parent Widget of the Widgets added to the layout
window = QWidget()

# Create the Horizontal Box Layout Manager, setting `window` as parent by passing it in the constructor
layout = QHBoxLayout(window)

# Create and add the QPushButton Widgets to the `layout`
layout.addWidget(QPushButton('One'))
layout.addWidget(QPushButton('Two'))
layout.addWidget(QPushButton('Three'))
layout.addWidget(QPushButton('Four'))
layout.addWidget(QPushButton('Five'))

# Show the parent Widget
window.show()

# Run the main Qt loop
sys.exit(app.exec())

Une fois que nous avons exécuté ce code, nous pouvons voir la fenêtre suivante sur notre écran :

Cette fenêtre contient 5 boutons disposés horizontalement, de gauche à droite.

3. QGridLayout

Un QGridLayout est utilisé lorsque nous voulons organiser les Widgets dans une grille de lignes et de colonnes. Dans cette grille, en utilisant les coordonnées, nous pouvons définir la position relative de chaque Widget comme :(ligne, colonne).

Remarque : Les deux row et column doivent être des nombres entiers.

QGridLayout utilise également tout l'espace qu'il obtient de la mise en page ou du Widget de son parent et le divise en plusieurs cases. Comme avec les précédents Layout Managers, chaque Widget va dans sa propre boîte. Le nombre de cases est automatiquement calculé en fonction du nombre de Widgets et de leurs coordonnées.

Utilisons un QGridLayout au lieu de la mise en page horizontale :

#!/usr/bin/python

# Import all needed modules
import sys
from PyQt6.QtWidgets import QApplication, QPushButton, QGridLayout, QWidget

# Create the Qt Application
app = QApplication(sys.argv)

# Create the parent Widget
window = QWidget()

# Create the buttons
button1 = QPushButton('One')
button2 = QPushButton('Two')
button3 = QPushButton('Three')
button4 = QPushButton('Four')
button5 = QPushButton('Five')

# Create the QGrid Layout Manager
layout = QGridLayout(window)

# Add button Widgets to the QGridLayout
# addWidget([object], [row number], [column number])
layout.addWidget(button1,0,0)
layout.addWidget(button2,1,0)
layout.addWidget(button3,2,0)
layout.addWidget(button4,0,1)
layout.addWidget(button5,0,2)

# Show the parent Widget
window.show()

# Run the main Qt loop
sys.exit(app.exec())

Une fois que nous avons exécuté ce code, nous pouvons voir la fenêtre suivante sur notre écran :

Cette fenêtre contient 5 boutons qui sont disposés comme nous l'avons spécifié dans le addWidget() méthode. La méthode elle-même accepte 3 arguments :

  1. Le Widget qui doit être placé dans la grille.
  2. La ligne dans laquelle il doit être placé.
  3. La colonne dans laquelle il doit être placé.

Il y a un quatrième argument facultatif, alignment , qui définit l'option d'alignement de chaque Widget à l'intérieur de sa boîte. La valeur par défaut (est Qt.Alignment.AlignCenter ) signifie que chaque Widget doit remplir toute sa case du centre vers l'extérieur. En savoir plus sur le Qt module dans les sections suivantes.

Enfin, il y a aussi un columnSpan et rowSpan argument, qui définit si un Widget s'étend sur plusieurs lignes ou colonnes :

addWidget(Widget, fromRow, fromColumn, rowSpan, columnSpan, Qt.Alignment)

Définissons les étendues de lignes et de colonnes ainsi qu'un Qt.Alignment (avant PyQt6, ce serait Qt.AlignLeft ):

# New import other than the ones already present
from PyQt6.QtCore import Qt

# addWidget([object], [row number], [column number], [columnSpan], [rowSpan], Qt.Alignment)
layout.addWidget(button1, 0, 0, 1, 1, Qt.Alignment.AlignLeft)
layout.addWidget(button2, 1, 0, 1, 1, Qt.Alignment.AlignLeft)
layout.addWidget(button3, 2, 0, 1, 1, Qt.Alignment.AlignLeft)
layout.addWidget(button4, 0, 1, 1, 1, Qt.Alignment.AlignLeft)
layout.addWidget(button5, 0, 2, 1, 1, Qt.Alignment.AlignLeft)

Vous pouvez AlignLeft , AlignTop , AlignBottom , AlignRight et AlignCenter . En redimensionnant la fenêtre, nous verrons que chaque bouton est aligné à gauche de sa propre boîte, plutôt qu'au centre :

Alors que si nous utilisions AlignCenter ou laissé par défaut :

4. QFormLayout

Le QFormLayout facilite la création de mises en page de formulaires pour les applications de bureau. Il se compose de deux colonnes - une pour les étiquettes et une pour les entrées.

Typiquement, le Widget d'entrée est un QLineEdit , QSpinBox , QComboBox , ou Widgets d'entrée similaires. Créons un QFormLayout :

#!/usr/bin/python

# Import all needed modules
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QLineEdit

def addLabel(layout, text):
    layout.addWidget(QLabel(text))

# Create the Qt Application
app = QApplication(sys.argv)

# Create the parent Widget and the QVBoxLayout Layout Manager
window = QWidget()
layout = QVBoxLayout(window)

# Create a label Widget and add it to the layout
label = QLabel('Enter some text!')
layout.addWidget(label)

line_edit = QLineEdit()
layout.addWidget(line_edit)

# Create a QPushButton object with a caption on it
qbtn= QPushButton('Add Label')

# Add the QPushButton to the layout
layout.addWidget(qbtn)

# Close the application when the button is pressed
# Here I am using slots & signals, which I will demonstrate later in this tutorial
qbtn.clicked.connect(lambda:addLabel(layout, line_edit.text()))

# Show the parent Widget
window.show()

# Run the main Qt loop
sys.exit(app.exec())

Une fois que nous avons exécuté ce code, nous pouvons voir la fenêtre suivante sur notre écran :

Cette fenêtre contient 2 libellés et 2 QLineEdit champs ajoutés via le addRow() méthode. addRow() accepte 2 arguments :

  1. Texte de l'étiquette (chaîne)
  2. Widget d'entrée (QWidget )

La méthode créera et ajoutera automatiquement un nouveau QLabel objet avec notre labelText comme son texte. De plus, vous pouvez également ajouter un QLabel argument au lieu d'une chaîne, qui ignore la conversion automatique :

layout.addRow(QLabel('Nickname:'), QLineEdit())
layout.addRow(QLabel('Score:'), QLineEdit())

Cela se traduit également par :

Widgets

Maintenant que nous connaissons les gestionnaires de mise en page proposés par PyQt, passons à quoi ils gèrent. Les widgets sont un concept clé de Qt, et par conséquent de PyQt.

Un widget reflète un composant graphique de l'interface utilisateur. Une interface utilisateur est composée de plusieurs widgets, disposés dans la fenêtre. Chaque Widget contient une série d'attributs et de méthodes qui nous permettent de modéliser leur apparence et leur comportement.

Depuis PyQt5, il y a eu un remaniement des classes de base en différents modules. Il existe quelques modules fondamentaux de haut niveau utilisés par PyQt6, notamment :

  • Qt  :Tous les modules mentionnés ci-dessous peuvent être trouvés regroupés dans ce module unique.
  • QtCore :Le QtCore module contient tous les modules non graphiques de base, utilisés par d'autres modules. Signaux , Fentes , etc... sont implémentés dans ce module.
  • QtWidgets :Ce module contient la plupart des Widgets disponible dans PyQt6.
  • QtGui :QtGui étend le QtCore module et contient des composants d'interface graphique.
  • QtSql  :Ce module implémente l'intégration de base de données pour les bases de données SQL.
  • QtMultimedia  :Des fonctionnalités multimédia de bas niveau peuvent être trouvées dans ce module.
  • QtNetwork :Les classes utilisées pour implémenter la programmation réseau (Sockets, SSL Handling, Network sessions, DNS, ...) se trouvent dans ce module.

Dans cette section, nous nous concentrerons sur les QtWidgets module et les Widgets qu'il propose.

1. Libellés

Le Widget le plus populaire, le label , est le plus souvent utilisé pour expliquer le but ou l'utilisation de votre interface graphique, comme l'annotation à quoi sert un champ.
Nous pouvons créer une étiquette en appelant le QLabel classer. Gardez à l'esprit que ce Widget ne fournit aucune interaction avec l'utilisateur.

Nous pouvons modifier l'apparence visuelle d'une étiquette de différentes manières :

  • setAlignment() alignera la légende selon les constantes d'alignement, qui peuvent être les suivantes :
    • Alignment.AlignLeft
    • Alignment.AlignRight
    • Alignment.AlignCenter
    • Alignment.AlignJustify
  • Text() permet de récupérer le libellé d'un libellé.
  • setText() va, au lieu de récupérer la légende, définir la légende d'une étiquette.
  • setIndent() définira l'indentation.
  • setWordWrap() enveloppera les mots dans une étiquette, ou non, selon le boolean passé .

Maintenant, créons une petite application PyQt6 en utilisant uniquement des étiquettes, pour afficher quelques informations sur la Belgique :

#!/usr/bin/python
# Import all needed modules
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel
from PyQt6.QtCore import Qt

# Create the Qt Application
app = QApplication(sys.argv)

# Create the parent Widget and the QVBoxLayout Layout Manager
window = QWidget()
layout = QVBoxLayout(window)

# Create a label beforehand
firstLabel = QLabel('Countrycode: BE')
secondLabel = QLabel('Brussels waffles are the best food ever.')

# Add labels to layout, creating an anonymous label while adding
layout.addWidget(firstLabel)
layout.addWidget(secondLabel, alignment = Qt.Alignment.AlignJustify)
layout.addWidget(QLabel('The Belgian flag consists of the colors black, yellow and red', wordWrap=True), alignment = Qt.Alignment.AlignLeft)

# using setText() we can change the caption of a label
firstLabel.setText('Belgium is a country located in Europe')
firstLabel.setAlignment(Qt.Alignment.AlignRight)

# Show the parent Widget
window.show()

# Run the main Qt loop
sys.exit(app.exec())

Vous pouvez créer un QLabel au préalable comme avec firstLabel . Ensuite, même après l'avoir ajouté à une mise en page, vous pouvez le manipuler et définir le texte, l'alignement, etc. via ses méthodes de réglage. Les derniers états, tels que définis par les setters, seront dessinés sur la fenêtre à la fin.

Si vous souhaitez éviter de créer des objets à l'avance et d'appeler de nombreuses méthodes, vous pouvez simplement créer un widget et l'ajouter juste après, dans le addWidget() appeler lui-même. Nous avons défini le wordWrap argument du troisième QLabel à vrai, puisqu'il est un peu plus long que les deux autres et que nous voudrions peut-être envelopper les mots au cas où ils seraient plus longs que la fenêtre ne peut en contenir.

Remarque : Depuis PyQt6, le Qt fait partie de PyQt6.QtCore , et le Align_ les options font partie du Alignment classe - résultant en Qt.Alignment.Align_ appels. Avant PyQt6, Qt faisait partie du PyQtX module, pas le QtCore module, et le Align_ les options faisaient partie de Qt donc les appels ressembleraient plus à - Qt.Align_ à la place.

Si nous exécutons ce code, nous verrons nos trois étiquettes, alignées selon notre Alignment paramètres :

2. Signaux et emplacements

Les signaux et les slots dans PyQt sont utilisés pour communiquer entre les objets. Ce mécanisme est une caractéristique centrale du framework Qt.

Par exemple, si un utilisateur clique sur Supprimer bouton, nous voulons le delete() de la fenêtre fonction à appeler. Pour cela, les 2 Widgets doivent communiquer entre eux.

Lorsqu'un événement se produit, un signal est émis par le Widget correspondant. Les widgets disponibles dans Qt ont de nombreux signaux prédéfinis, mais vous pouvez toujours créer des signaux personnalisés supplémentaires.

Un emplacement est une fonction appelée en réponse à un signal . Encore une fois, les widgets disponibles dans Qt ont de nombreux emplacements prédéfinis, mais il est très courant de créer les vôtres.

Les fonctionnalités les plus utiles de Signals and Slots incluent :

  • Un signal peut être connecté à un autre signal
  • Un signal peut être connecté à un ou plusieurs slots
  • Un slot peut être connecté à un ou plusieurs signaux

La syntaxe générale pour connecter un signal à un slot est :

widget.signal.connect(slot_function) 

Ce code connectera le slot_function à Widget.signal , et chaque fois que le signal est émis, le slot_function() la fonction sera appelée.

Pour éviter tout comportement inattendu, il est important d'annoter chaque fonction d'emplacement avec le @pyqtSlot() décorateur :

from PyQt6.QtCore import pyqtSlot

# Slot function - Note the @pyqtSlot() annotation!
@pyqtSlot()
def hello_world():
  print('Button is clicked, Hello World!')

Maintenant, créons une application qui utilise le mécanisme Signals and Slots, en mettant un bouton qui imprime simplement un message sur la console :

#!/usr/bin/python
# Import all needed modules
import sys
from PyQt6.QtWidgets import QApplication, QPushButton
from PyQt6.QtCore import pyqtSlot

@pyqtSlot()
def hello_world():
  print('You shall not pass!')

# Create the Qt Application
app = QApplication(sys.argv)

# Create a QPushButton Object
button = QPushButton('Click me')

# Connect the button to the hello_world slot function
button.clicked.connect(hello_world)

# Show the button to the user
button.show()

# Run the main Qt loop
sys.exit(app.exec())

Une fois que nous avons exécuté ce code, nous pouvons voir la fenêtre suivante sur notre écran :

Après avoir exécuté ce code et cliqué sur le bouton, il affiche le texte suivant dans la console :

You shall not pass!

3. Boutons

Maintenant que nous pouvons étiqueter d'autres composants GUI sur une application - jetons un coup d'œil au premier composant interactif que nous allons implémenter - un QButton . Les boutons mènent à des résultats - dans notre cas, ils peuvent être utilisés pour appeler certaines fonctions. Il existe quelques boutons par défaut prédéfinis qui sont OK, Oui, Non, Annuler, Appliquer et Fermer , cependant, vous pouvez également y ajouter du texte personnalisé.

Vous pouvez attacher un gestionnaire d'événements à un bouton qui déclenche une fonction ou tout autre morceau de code lorsqu'un bouton est enfoncé. Créons un bouton qui permet à l'utilisateur d'ajouter un QLabel à l'écran.

Une fois qu'un utilisateur saisit du texte dans un QLineEdit , et qu'une pression sur un bouton a été détectée - nous collecterons les données à partir d'un QLineEdit , et utilisez ce texte pour définir le texte d'un nouveau QLabel , qui est ensuite ajouté à la mise en page.

Étant donné que les boutons s'attendent à ce qu'une fonction appelable soit transmise en tant que gestionnaire d'événements de clic, nous allons définir une nouvelle fonction add_label() qui peut être utilisé pour ajouter n'importe quel QLabel à la mise en page spécifiée :

def addLabel(layout, text):
    layout.addWidget(QLabel(text))

Maintenant, écrivons notre interface graphique et appelons cette fonction avec le texte fourni par l'utilisateur :

#!/usr/bin/python
# Import all needed modules
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QLineEdit

def addLabel(layout, text):
    layout.addWidget(QLabel(text))
    
# Create the Qt Application
app = QApplication(sys.argv)

# Create the parent Widget and the QVBoxLayout Layout Manager
window = QWidget()
layout = QVBoxLayout(window)

# Create a Qlabel Widget and add it to the layout
label = QLabel('Enter some text!')
layout.addWidget(label)

# Create a QLineEdit to collect user data
line_edit = QLineEdit()
layout.addWidget(line_edit)

# Create a QPushButton object with a caption on it
qbtn= QPushButton('Add Label')
layout.addWidget(qbtn)

# When clicked, perform a callable function - `addLabel()`
qbtn.clicked.connect(lambda:addLabel(layout, line_edit.text()))

# Show the parent Widget
window.show()

# Run the main Qt loop
sys.exit(app.exec())

Une fois que nous avons exécuté ce code, nous pouvons écrire du texte dans le QLineEdit champ, qui est ajouté à la mise en page en tant que QLabel une fois que nous appuyons sur Ajouter une étiquette :

4. Modifications de ligne

Nous avons brièvement examiné le QLineEdit widget deux fois maintenant - prenons un moment pour voir ce qu'il offre. Comme vu précédemment, il permet aux utilisateurs de saisir une ligne de texte - c'est le moyen rudimentaire de collecter des données utilisateur, que ce soit pour l'ajout ou la modification de données déjà existantes. Nous pouvons bien sûr effectuer des opérations courantes telles que copier , coller , annuler , refaire tout en y écrivant du texte.

Certaines des méthodes courantes que vous utiliserez avec eux sont :

  • setAlignment() alignera à nouveau la légende selon les constantes d'alignement
  • setMaxLength() définit un nombre maximum de caractères que l'utilisateur ne peut pas dépasser
  • text() - récupère le texte dans un QLineEdit
  • setText() - définit le texte dans un QLineEdit
  • clear() effacera tout le contenu du QLineEdit

Réécrivons l'exemple précédent, mais cette fois nous avons déjà du texte prédéfini dans un QLineEdit , modifier un QLabel déjà existant au lieu d'en ajouter un nouveau - et explorez brièvement l'utilisation des PyQt Slots , qui seront abordés plus en détail plus loin dans le guide.

Nous allons créer une application de devis rudimentaire, qui contient un corpus de citations célèbres et vous en donne une au hasard sur demande. Vous pouvez développer cette liste en en ajoutant une nouvelle et en cliquant sur Ajouter un devis , qui est ensuite inclus dans le pool de devis lorsque vous décidez d'en obtenir un nouveau au hasard via Obtenir un devis aléatoire :

#!/usr/bin/python
# Import all needed modules
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QLineEdit
from PyQt6.QtCore import pyqtSlot
import random

# Deifne helper functions as PyQt Slots
@pyqtSlot()
def randomQuote():
  # Set label to random quote from the list
  quoteLabel.setText(random.choice(quotes))

@pyqtSlot()
def addQuote():
    # Add new quote to the list and clear the input field
    quotes.append(newQuoteLineEdit.text())
    newQuoteLineEdit.clear()

app = QApplication(sys.argv)
window = QWidget()
layout = QVBoxLayout(window)

# Default quote list
quotes = ['Do or do not, there is no try.', 'The meaning of life is 42']

# Get a random quote for the user
quoteLabel = QLabel(random.choice(quotes))

# QLineEdit field to collect new quote information, and a button for it
newQuoteLineEdit = QLineEdit('Add new quote...')
addQuoteButton = QPushButton('Add New Quote')

# Button to get random quote
getQuoteButton = QPushButton('Get Random Quote')

# Add the previous Widgets to the layout
layout.addWidget(newQuoteLineEdit)
layout.addWidget(quoteLabel)
layout.addWidget(addQuoteButton)
layout.addWidget(getQuoteButton)

# On click - call the slots (functions)
getQuoteButton.clicked.connect(randomQuote)
addQuoteButton.clicked.connect(addQuote)

# Show the parent Widget
window.show()

# Run the main Qt loop
sys.exit(app.exec())

Cela se traduit par :

5. Boîtes combinées

Comboboxes permettre aux utilisateurs de choisir parmi une liste d'options - similaire au <select> balise en HTML. Ceux-ci peuvent être atteints via le QComboBox Widget. Le QComboBox de base est un widget en lecture seule, ce qui signifie que l'utilisateur doit choisir exclusivement dans la liste prédéfinie et ne peut pas ajouter ses propres options. Cependant, ils peuvent également être modifiables, ce qui permet à l'utilisateur d'ajouter une nouvelle option si aucune ne correspond à ses besoins.

Vous trouverez ci-dessous les méthodes les plus couramment utilisées de la classe QComboBox :

  • addItem() ajoute une chaîne à la collection
  • addItems() ajoutera chacune des chaînes de la liste donnée à la collection
  • Clear() est utilisé pour supprimer tous les éléments de la collection
  • count() est utilisé pour récupérer le nombre d'éléments dans la collection
  • currentText() est utilisé pour récupérer le texte de l'élément actuellement sélectionné
  • itemText() accepte un index argument et renvoie le texte de cet élément
  • currentIndex() renvoie l'index de l'élément actuellement sélectionné

Créons une mini application de commande, où un utilisateur sélectionne un élément dans un menu et entre un commentaire pour le restaurant. Ensuite, lorsqu'un bouton est cliqué - cet ordre est montré à l'utilisateur :

#!/usr/bin/python
# Import all needed modules
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QLineEdit, QComboBox
from PyQt6.QtCore import pyqtSlot

@pyqtSlot()
def placeOrder():
    order_format = "Placed order for {} with comment '{}'"
    layout.addWidget(QLabel(order_format.format(comboBox.currentText(), commentLineEdit.text())))

app = QApplication(sys.argv)

window = QWidget()
layout = QVBoxLayout(window)

label1 = QLabel('Pick one of the following options:')
comboBox = QComboBox()
comboBox.addItems(['Pasta', 'Pizza', 'Lasagna'])

layout.addWidget(label1)
layout.addWidget(comboBox)

commentLineEdit = QLineEdit('Comment for the restaurant...')
placeOrderButton = QPushButton('Place order')

layout.addWidget(commentLineEdit)
layout.addWidget(placeOrderButton)

placeOrderButton.clicked.connect(placeOrder)

window.show()
sys.exit(app.exec())

Maintenant, passons une commande et joignons-y une demande :

6. Boutons radio et cases à cocher

Les boutons radio et les cases à cocher sont principalement utilisés dans le même but - permettant à quelqu'un de sélectionner une option parmi plusieurs. La seule différence est que les boîtes radio sont utilisées lorsque nous souhaitons limiter l'utilisateur à sélectionner une option, tandis que les cases à cocher sont utilisées lorsque nous souhaitons autoriser l'utilisateur à sélectionner plusieurs options.

Par exemple, nous pouvons forcer l'utilisateur à choisir entre être un nouveau ou un ancien client (les deux ne peuvent pas être les deux en même temps), mais lui permettre de sélectionner plusieurs services auxquels il souhaite s'inscrire.

Ceux-ci sont implémentés en tant que QRadioButton et QCheckBox , naturellement. Nous pouvons vérifier s'ils sont cochés, les activer ou non, définir leur texte ainsi que récupérer le texte de leurs étiquettes :

  • setChecked() coche le bouton radio ou la case à cocher
  • setText() définit le libellé associé au bouton ou à la case à cocher
  • text() récupérera le libellé du bouton/de la case à cocher
  • isChecked() vérifie si le bouton/la case à cocher est sélectionné ou non

Créons une application simple qui permet aux utilisateurs de choisir entre quelques-uns des services proposés par un lave-auto imaginaire :

#!/usr/bin/python
# Import all needed modules
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QRadioButton, QCheckBox

app = QApplication(sys.argv)
window = QWidget()
layout = QVBoxLayout(window)

label_customer = QLabel('Pick one of the following options:')

# Create two radio buttons for the customer, assuming they might be a new customer
qradioButton = QRadioButton('Old Customer')
qradioButton2 = QRadioButton('New Customer')
qradioButton2.setChecked(True)

layout.addWidget(label_customer)
layout.addWidget(qradioButton)
layout.addWidget(qradioButton2)

label_service = QLabel("Pick the services you'd like:")
qCheckBox = QCheckBox('Car Wash')
qCheckBox2 = QCheckBox('Car Polish')
qCheckBox3 = QCheckBox('Vacuuming')

layout.addWidget(label_service)
layout.addWidget(qCheckBox)
layout.addWidget(qCheckBox2)
layout.addWidget(qCheckBox3)

window.show()
sys.exit(app.exec())

Cela nous invite à une application de type enquête qui nous permet de choisir si nous sommes un ancien ou un nouveau client, et nous permet de choisir entre les services proposés par le lave-auto :

7. Afficher des données à l'aide d'un widget de tableau

QTableWidget est un widget qui, sans trop de configuration, nous permet de créer de superbes tableaux de type Excel dans PyQt, dans lesquels nous pouvons afficher des données.

Gardez à l'esprit que l'utilisation d'un QTableWidget n'est pas le seul moyen d'afficher des informations dans des tableaux. Les modèles de données peuvent être créés et affichés à l'aide du QTableView Widget également. Cependant, le QTableWidget utilise intrinsèquement un QTableView sous le capot pour créer un tableau, nous allons donc utiliser l'approche de niveau supérieur consistant à utiliser le tableau dès le départ.

Étant donné la nature des tables en colonnes, nous pouvons facilement créer des dictionnaires pour contenir des données ou même des listes de listes. Lors de la création d'un tableau, nous voudrons définir le nombre de colonnes et de lignes avant en y ajoutant des données, puis remplissez-le simplement à travers des boucles :

  • setRowCount() définit le nombre de lignes
  • setColumnCount() définit le nombre de colonnes
  • setHorizontalHeaderLabels() définit les étiquettes des en-têtes horizontaux

Créons maintenant une application simple qui contient un tableau avec plusieurs pays nordiques et leurs capitales :

#!/usr/bin/python
# Import all needed modules
import sys
from PyQt6.QtWidgets import (QApplication, QTableWidget, QTableWidgetItem)
from PyQt6.QtGui import QColor

# Declare our table values
nordic_countries = [('Norway', 'Oslo', 'Yes'),
          ('Iceland', 'Reykjavik', 'Yes'),
          ('Denmark', 'Copenhagen', 'Yes'),
          ('Belgium', 'Brussels','No')]
          
# Create the Qt Application
app = QApplication(sys.argv)
table = QTableWidget()

# Configure QTableWidget to have a number of rows equivalent to the amount of items from the nordic_countries struct
table.setRowCount(len(nordic_countries))

# Since every country in our 'nordic_countries' variable has the same amount of attributes
# we take the amount (3) of the first country and use this as the number of columns
table.setColumnCount(len(nordic_countries[0]))

# Set the Horizontal headers using setHorizontalHeaderLabels()
table.setHorizontalHeaderLabels(['Country', 'Capital', 'Scandinavian?'])

# Loop through every country in our 'nordic_countries' variable
for i, (country, capital, scandinavian_bool) in enumerate(nordic_countries):

    # Make a QTableWidgetItem --> acts as an item in a table
    item_country = QTableWidgetItem(country)
    item_capital = QTableWidgetItem(capital)
    item_scandinavian_bool = QTableWidgetItem(scandinavian_bool)

    # Set the items: item, index, QTableWidgetItem
    table.setItem(i, 0, item_country)
    table.setItem(i, 1, item_capital)
    table.setItem(i, 2, item_scandinavian_bool)

# Finally show the table
table.show()

# Launch the application
sys.exit(app.exec())

Une fois que nous avons exécuté ce code, nous pouvons voir la fenêtre suivante sur notre écran :

8. Afficher des données à l'aide d'un widget d'arborescence

Les widgets d'arborescence sont vraiment utiles pour afficher des structures arborescentes telles que des hiérarchies de fichiers ou des sous-listes relatives à des listes d'éléments spécifiques. Pour s'adapter à ce type de Widget, PyQt propose QTreeWidget .

Semblable à la façon dont le QTableWidget est construit sur QTableView - le QTreeWidget est construit sur QTreeView .

L'arborescence se compose d'en-têtes et articles . Les en-têtes sont les noms des colonnes. Chaque élément peut avoir plusieurs éléments qui lui sont attribués. Un élément peut, par exemple, être un répertoire, tandis que ses propres éléments sont les fichiers de ce répertoire - ou un élément peut être une tâche, et ses éléments sont les personnes affectées à cette tâche.

Certaines des méthodes courantes que nous utiliserons pour travailler avec les widgets d'arbre sont :

  • setHeaderLabels() définit le nom de la colonne pour le widget d'arborescence
  • clear() pour effacer toutes les données de l'arborescence
  • editItem() pour modifier un certain élément dans l'arborescence
  • addTopLevelItem() pour ajouter un élément de niveau supérieur
  • addTopLevelItems() pour ajouter une liste d'éléments de niveau supérieur

Chaque élément peut être affecté à un composant parent. Pour un élément de niveau supérieur, nous pouvons l'affecter au QTreeWidget lui-même, tandis que pour les éléments de niveau inférieur, nous pouvons les affecter à des éléments de niveau supérieur déjà existants. Vous pouvez aller aussi loin que vous le souhaitez, cependant, avoir trop de niveaux peut être déroutant pour l'utilisateur.

Allons-y et faisons une liste de courses rapide - avec Food et Furniture car les articles de niveau supérieur (catégories d'articles que nous aimerions acheter) et leurs enfants seront les articles eux-mêmes :

#!/usr/bin/python
# Import all needed modules
import sys
from PyQt6 import QtWidgets

app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QWidget()
layout = QtWidgets.QVBoxLayout(window)

# Create the QTreeWidget Widget
tree_widget = QtWidgets.QTreeWidget()

# Set the column name for the Tree Widget
tree_widget.setHeaderLabels(['Items', 'Total Cost'])

# Populate first tree with QTreeWidgetItem objects
foodList = QtWidgets.QTreeWidgetItem(tree_widget, ['Food', '€ 15'])
QtWidgets.QTreeWidgetItem(foodList, ['Apples', '€ 6'])
QtWidgets.QTreeWidgetItem(foodList, ['Pears', '€ 4'])
QtWidgets.QTreeWidgetItem(foodList, ['Oranges', '€ 5'])

# Populate second tree with QTreeWidgetItem objects
furnitureList = QtWidgets.QTreeWidgetItem(tree_widget, ['Furniture', '€ 225'])
QtWidgets.QTreeWidgetItem(furnitureList, ['Table', '€ 150'])
QtWidgets.QTreeWidgetItem(furnitureList, ['Chairs', '€ 75'])

layout.addWidget(tree_widget)

window.show()
sys.exit(app.exec())

Une fois que nous avons exécuté ce code, nous pouvons voir la fenêtre suivante sur notre écran :

Conclusion

Dans ce guide, nous avons sauté dans PyQt - le wrapper de Python pour la populaire bibliothèque Qt.

Nous avons examiné certains des concepts clés de la bibliothèque et avons commencé à travailler avec elle via les gestionnaires de mise en page, nous nous sommes familiarisés avec les widgets et avons créé plusieurs applications de démonstration très simples qui montrent comment vous pouvez les utiliser.