Une application graphique, aussi appelée GUI en anglais, désigne un affichage pour représenter un programme à un utilisateur. Par exemple, l'application "Calculatrice" qui est de base sur Windows est une application graphique.
Vous savez désormais, si vous avez lu mes autres articles, que Python possède de nombreuses applications. Et bien, Python nous permet également de réaliser des interfaces graphiques. Pour cela on dispose de deux bilbiothèques principales : PyQt ou Tkinter.
Dans cet article, nous allons parler uniquement de PyQt, en revanche il est utile de savoir qu'il existe une autre librairie vous permettant de réaliser des GUI. En effet, en fonction de vos projets, il peut-être soit plus judicieux d'utiliser PyQt, ou alors Tkinter.
Tkinter est beaucoup plus simple et plus légère que PyQt. Cela vous permet de mettre rapidement et simplement en place une application graphique. Mais l'inconvénient est que les possibilités sont plus réduites avec Tkinter.
Aussi, les GUI Tkinter sont difficilement personnalisables, alors qu'avec PyQt vous pouvez simplement appliquer des feuilles de style (CSS) à votre application.
Et finalement, le fonctionnement interne des applications créées par ces bibliothèques est différent. Tandis que Tkinter fonctionne avec des évènements pour gérer les interactions, PyQt fonctionne avec un système de signaux et slots, qui je l'avoue est un peu déroutant au début.
En conclusion, je pense qu'il est bien de connaître les deux bibliothèques, éventuellement de savoir les utiliser toutes les deux, afin de pouvoir décider la quelle utiliser en fonction du projet. Tkinter sera utile pour des petits projets, devant être mis en place rapidement. PyQt sera préférable lorsque les projets sont plus importants ou à plus long terme.
Personnellement, si vous deviez en apprendre une seule entre les deux, je vous conseillerai PyQt. Le temps d'apprentissage et la prise en main est plus longue, mais les possibilités sont infinies lorsque vous la maîtrisez bien.
Après cette petite introduction, on va pouvoir plonger dans le vif du sujet.
Commençons par le commencement, il faut installer PyQt. Pour la version, vous avez le choix, soit PyQt5, soit PyQt6. Les deux sont quasiment identiques, j'ai toujours travaillé avec PyQt5 alors pour ce tutoriel je vais utiliser PyQt5, mais normalement tout devrait fonctionner de la même façon avec PyQt6.
Vous êtes libres d'installer PyQt où vous voulez, je vous recommande de créer un environnement virtuel. Une fois que c'est bon, voici la commande :
pip install PyQt5
Bien, c'est l'heure de créer notre toute première fenêtre. Commençons par les imports. PyQt est une très grosse librairie, donc les imports peuvent être assez complexes. Pour commencer, nous allons importer uniquement les widgets dont nous avons besoin (nous reviendrons toute à l'heure sur ce que sont les widgets).
from PyQt5.QtWidgets import QApplication, QLabel
Le widget de base à toute application Qt est une QApplication
. On commence donc par en créer une :
import sys
app = QApplication(sys.argv)
Mais c'est quoi ce "sys.argv" ?
Ce sont les arguments passés à l'exécution de votre script. Nous reviendrons là dessus dans un autre article si vous ne savez pas ce que c'est, en tout cas sachez qu'il faut passer des arguments pour instantier une QApplication
, au minimum passez en argument une liste vide.
Bien, maintenant que nous avons notre fenêtre, nous allons la décorer un tout petit peu. On va y ajouter un label (texte). Pour cela, on instantie un QLabel
, avec le texte qu'on souhaite :
label = QLabel("Test")
Cependant, ce code ne fera rien. Il faut dire à notre app qu'on souhaite montrer notre label, pour cela :
label.show()
Finalement, il faut exécuter notre app. En effet, pour l'instant on l'a juste instantié. On utilise donc sa méthode exec_
:
app.exec_()
Normalement, votre fichier .py devrait ressembler à ça :
import sys
from PyQt5.QtWidgets import QApplication, QLabel
app = QApplication(sys.argv)
label = QLabel("Test")
label.show()
app.exec_()
Et vous devriez être en mesure de comprendre à peu près chaque ligne. Exécutez votre script et vous verrez qu'une petite fenêtre apparaît, c'est que tout a marché !
Les widgets sont tout ce que vous voyez dans une application PyQt. Si vous mettez du texte, ce sont des widgets, les boutons sont des widgets, les curseurs sont des widgets, etc... Même votre fenêtre est un widget.
Les widgets peuvent être imbriqués les uns dans les autres. Par exemple, ma fenêtre est un widget contenant d'autres widgets comme des boutons, qui eux-même contiennent des widgets comme du texte.
Il y en a beaucoup, et vous allez certainement en utiliser une bonne partie si vous faites une application Qt. Nous allons voir le QLabel
et le QPushButton
, pour les autres vous devrez fouiller dans la doc !
C'est simplement un widget contenant du texte. On lui passe en paramètre le texte à afficher lorsqu'on le construit.
label = QLabel("example")
C'est un widget représentant un bouton. De la même manière qu'un QLabel, on lui passe en paramètre le texte du bouton à la construction.
button = QPushButton("my button")
C'est tout ? Comment on fait pour assigner des actions lors d'un clic sur le bouton ?
Nous verrons ça après, lorsqu'on étudiera les signaux et les slots :)
Les layouts sont également des widgets. En revanche, ils sont un peu particuliers car ils n'ont pas d'apparence graphique. Ils permettent simplement de dire comment ranger les widgets dans la fenêtre. Par exemple, imaginez que vous ayez une armoire avec plusieurs tiroirs. Cette armoire peut avoir plusieurs portes, plusieurs tiroirs, etc... Et vous pouvez ranger des objets dedans dans les emplacements dédiés. Dans ce cas, vos objets seront bien rangés et organisés selon la structure définie par l'armoire. C'est à peu près ce qu'on peut faire avec les layouts, sauf qu'à la différence de l'armoire, les layouts et les tiroirs sont invisibles, seuls les objets contenus dedans sont visibles.
Commençons par créer notre première layout, une QVBoxLayout
. C'est une layout qui nous permet d'empiler des widgets les uns sur les autres.
from PyQt5.QtWidgets import QVBoxLayout
vbox = QVBoxLayout()
Maintenant qu'on a créé notre armoire à rangements verticale, il faut la remplir d'objets.
button1 = QPushButton("Button 1")
button2 = QPushButton("Button 2")
vbox.addWidget(button1)
vbox.addWidget(button2)
Notre armoire est remplie de deux boutons qui seront affichés verticalement. Mais maintenant, on fait quoi ? Notre armoire doit être dans une maison pour qu'elle soit utile (bon, pas forcément, mais en toute logique si). Notre maison est la fenêtre de l'application, c'est dedans qu'on peut ranger toutes nos armoires. Attention cependant, il faut distinguer la fenêtre, de l'application.
On commence par créer une application, dans laquelle on crée une fenêtre, et à laquelle on ajoute notre armoire (layout). Finalement on affiche notre fenêtre, et on exécute le tout :
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
app = QApplication([])
window = QWidget()
vbox = QVBoxLayout()
button1 = QPushButton("Button 1")
button2 = QPushButton("Button 2")
vbox.addWidget(button1)
vbox.addWidget(button2)
window.setLayout(vbox)
window.show()
app.exec()
Normalement vous obtenez une belle fenêtre avec vos deux boutons superposés !
Comme je l'ai évoqué plus haut, afin de modifier le design dans PyQt, on peut utiliser des feuilles de style CSS. Mais commençons par le plus simple : les styles de base.
PyQt propose plusieurs styles de base, sur lesquels on peut basculer facilement. Ils changent complètement l'apparence de votre application. En voici quelques uns :
Pour appliquer un style, on utilise la méthode setStyle
de notre application :
app.setStyle("Windows")
Peut-être que vous aimeriez simplement changer les couleurs plutôt que de refaire tout un style. Pour cela on utilise QPalette
. Elle permet de réaliser un mapping des couleurs. Par exemple :
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPalette
palette = QPalette()
palette.setColor(QPalette.ButtonText, Qt.green)
app.setPalette(palette)
Vous retrouverez tous les mappings possibles dans la documentation de PyQt.
Finalement, la façon la plus complète de modifier le design d'une application PyQt, c'est en utilisant les feuilles de style. Pour cela, il faut simplement stocker votre feuille de style dans une chaîne de caractères, et modifier le style comme ceci :
stylesheet = "QPushButton { margin-bottom: 5ex; }"
app.setStyleSheet(stylesheet)
Ces concepts sont peut-être les plus durs à comprendre dans PyQt. Un signal est envoyé quand une action est réalisée, et un slot est une action qui s'exécute en réponse à se signal. Par exemple, lorsqu'on clique sur un bouton, cela envoie un signal pour dire que le bouton a été cliqué, et il est possible de connecter ça à un slot pour afficher du texte en réponse à ce clic, ou lancer un téléchargement, etc...
PyQt propose de nombreux signaux avec ses widgets. Par exemple, le signal évoqué plus haut peut-être récupéré de cette façon :
button = QPushButton("Hello")
button.clicked.connect(...)
On a donc widget.signal.connect(fonction)
.
Si je souhaite afficher du texte en console lorsque je clique sur mon bouton, je le fais de cette façon :
def hello():
print("hello")
button.clicked.connect(hello)
Il faut toujours connecter une fonction. Donc si j'essaie de faire ceci :
button.clicked.connect(hello())
J'obtiendrai une erreur, car hello()
n'est pas une fonction, mais la valeur renvoyée par hello
. C'est donc là que les fonctions lambda deviennent utiles, comme ça vous puvez éviter d'écrire trop de fonctions basiques.
button.clicked.connect(lambda x: print("hello"))
Ici, il n'y aura pas de problèmes car nous passons une fonction en paramètre.
Vous trouverez plus d'infos sur les signaux de chaque widget dans la documentation de PyQt !
Ce n'est que le début de votre voyage avec PyQt. Il y a tellement de choses à voir que je ne peux pas faire qu'un seul article, il y en aura certainement un autre. En attendant il faut pratiquer, car ce n'est pas une librairie simple à maîtriser. Vous avez tout de même quelques bases et de quoi commencer à expérimenter maintenant.
Aussi, je vous ai dit à plusieurs reprises d'aller voir la documentation de PyQt. En effet, je ne peux pas tout expliquer, et la documentation de PyQt est tellement bien faite qu'il ne faut pas s'en priver. D'autant plus que c'est intéressant d'apprendre à fouiller dans les documentations.
J'espère que cet article vous aura plu, si c'est le cas n'hésitez-pas à me faire un retour ! Et si vous avez des questions je serai ravi d'y répondre.
On se retrouve prochainement pour aller plus loin avec PyQt !