Qt est un ensemble de librairies, initialement développées en C++, pour le développement d’interfaces graphiques. Actuellement, deux versions coexistent : Qt 5 et Qt 6. Ces bibliothèques fournissent également des fonctionnalités pour la gestion des réseaux, des processus indépendants, la gestion de bases de données…

PyQt est un ensemble de bibliothèques libres adaptées de Qt. Les fonctionnalités présentes dans ces bibliothèques permettent notamment :

  • de créer des interfaces graphiques
  • de gérer les événements associés aux éléments graphiques
  • de mettre en page les éléments graphiques

Installation

L’installation de PyQt se fait par l’une des commandes suivantes (dans un invité de commande sous Windows par exemple) selon la version que vous souhaitez installer :

pip install pyqt5
pip install pyqt6

La version 5 de PyQt est pré-installée avec la distribution Anaconda 3.

Eléments de base

Eléments graphiques

Pour réaliser des interfaces graphiques, il est indispensable de saisir la différence entre un contenant, les éléments qu’il peut contenir et une mise en page.

Les contenants (QWidget) permettent d’accueillir des éléments graphiques. Par défaut, ces éléments graphiques…

Mise en page : https://realpython.com/python-pyqt-layout/

Deux catégories d’interfaces graphiques

Il existe deux grandes catégories d’interface graphique réalisables grâce à PyQt :

  • QMainWindow, qui produit une fenêtre complète, pouvant intégrer des menus, une barre d’état et un contenant central
  • QWidget, qui produit uniquement un contenant graphique, sans “décoration” autour

La fenêtre principale

Le code suivant permet d’établir une fenêtre de base de type QMainWindow (PyQt5.QtWidgets), sans éléments graphiques.

Cette structure est néanmoins indispensable pour toute future fenêtre d’application.

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication

"""
MainWindow class
"""
class MainWindow(QMainWindow):
    
    def __init__(self):
        super().__init__(parent=None)
        
    def closeEvent(self, event):
        QApplication.quit()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())

Titre et dimensions

Il est possible d’ajouter un titre à notre fenêtre, ainsi que de spécifier les dimensions et la position dans l’écran.

    def __init__(self):
        super().__init__(parent=None)
        self.setWindowTitle("Ma première application PyQt")
        self.setGeometry(100, 100, 500, 200)

La fonction setWindowTitle permet de donner un titre à la fenêtre, qui s’affichera dans la barre du haut.

La fonction setGeometry permet de définir la position, par l’intermédiaire des deux premiers arguments de la fonction qui sont la position X et Y dans l’écran, et la dimension de la fenêtre souhaitée, par l’intermédiaire des deux arguments suivants correspondant à la largeur et la hauteur.

Des premiers éléments graphiques

Contenant principal

Afin de placer des éléments graphiques (textes, images, boutons, listes à choix…), il faut au préalable ajouter un contenant de type QWidget comme élément principal de la fenêtre précédente.

Il faut ajouter cet objet à la liste des modules à importer :

from PyQt5.QtWidgets import QWidget

Il faut ajouter ensuite ces lignes dans la fonction __init__ :

        self.mainWidget = QWidget()
        self.setCentralWidget(self.mainWidget)

Graphiquement, en lançant se nouveau programme, aucun changement de comportement. Rien ne s’affiche.

Un premier texte

Il est possible d’ajouter du texte par l’intermédiaire d’un objet de type QLabel. Cet objet nécessite 2 paramètres : le premier correspond au texte à afficher (il peut être modifié par la suite) et la fenêtre (ou le contenant) dans lequel il doit apparaître.

Il faut ajouter cet objet à la liste des modules à importer :

from PyQt5.QtWidgets import QLabel

Il faut ajouter ensuite cette ligne dans la fonction __init__ :

        self.my_label = QLabel('<h1>Mon application est geniale</h1>', self.mainWidget)

Le texte peut être formaté à l’aide des balises HTML (<h1> pour un titre de haut niveau par exemple). Il est également possible d’ajouter des “décorations” de type CSS.

Il est possible de modifier le texte d’un QLabel par l’utilisation de la fonction setText.

self.my_label.setText('<h2>Mon application est geniale</h2>')

Un peu d’interaction

Il est possible d’ajouter également des objets qui permettent à l’utilisateur d’interagir. Par exemple, nous pouvons insérer un bouton de type QPushButton.

Il faut ajouter cet objet à la liste des modules à importer :

from PyQt5.QtWidgets import QPushButton

Il faut ajouter ensuite cette ligne dans la fonction __init__ :

        self.my_button = QPushButton("Appuyez !", self.mainWidget)

Sans autres précautions (en particulier l’utilisation d’un gestionnaire de mise en page – Layout), l’application ressemble à cela. On s’aperçoit que le bouton se superpose au texte précédent. D’autre part, l’appui sur le bouton n’entraine aucune action…

Avant d’améliorer la mise en page, nous allons nous intéresser au déclenchement d’actions selon certains événements (par exemple le clic sur un bouton).

Evénements

PyQt permet de gérer les événements liés aux éléments graphiques.

Pour cela, il faut créer une fonction spécifique qui sera appelée lorsque l’événement aura lieu.

Par exemple, nous allons ici faire en sorte que lors de l’appui sur le bouton, son texte change et son interaction soit bloquée. On définit dans la classe MainWindow la nouvelle fonction buttonClicked (choix arbitraire du nom) suivante :

"""
MainWindow class
"""
class MainWindow(QMainWindow):
    ...
    def buttonClicked(self):
        self.my_button.setText("! INACTIF !")
        self.my_button.setEnabled(False)

Si vous relancez votre application, vous verrez que rien ne se passe… Nous n’avons pas encore lié cette action avec l’événement associé au clic sur le bouton.

Pour cela, nous allons utiliser la fonction connect associée au bon événement, ici clicked.

"""
MainWindow class
"""
class MainWindow(QMainWindow):
    
    def __init__(self):
        ...
        
        self.my_button.clicked.connect(self.buttonClicked)

Un peu de structuration

Dans la précédente application, on a pu constater que les éléments graphiques se superposent.

Afin de remédier à cela, il est indispensable d’ajouter un gestionnaire de mise en page (Layout Manager) à notre interface.

Il en existe plusieurs types, selon la disposition que vous souhaitez. Vous pouvez consulter des exemples à l’adresse suivante : https://realpython.com/python-pyqt-layout/

Dans l’exemple suivant, nous allons utiliser un gestionnaire vertical QVBoxLayout. Chaque nouvel élément ajouté est positionné à la fin d’une série verticale.

"""
MainWindow class
"""
class MainWindow(QMainWindow):
    
    def __init__(self):
        super().__init__(parent=None)
        ''' Main Window parameters '''
        self.setWindowTitle("Ma première application PyQt")
        self.setGeometry(100, 100, 500, 200)
        self.mainWidget = QWidget()
        self.setCentralWidget(self.mainWidget)
        
        ''' Graphical Elements '''
        self.my_label = QLabel('<h1>Mon application est geniale</h1>')
        self.my_button = QPushButton("Appuyez !")

        ''' Layout Manager '''
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.my_label)
        self.layout.addWidget(self.my_button)
        self.mainWidget.setLayout(self.layout)

        ''' Events '''
        self.my_button.clicked.connect(self.buttonClicked)

Dans l’exemple précédent, on replace le texte et le bouton l’un au dessus de l’autre à l’aide du gestionnaire QVBoxLayout associé au contenant graphique QWidget.

Il sera possible par la suite d’imbriquer certains gestionnaires à l’intérieur d’autres zones afin d’améliorer encore la mise en page de l’application.

Il est également possible de modifier les tailles des différents éléments.

Python / PyQt / Première interface graphique