Files
training.python.beginner/documentation/10-graphical-ui-extra.md
2025-07-04 19:26:39 +02:00

5.6 KiB

title, author
title author
Interfaces graphiques avec Pyside Steve Kossouho

Développer avec Pyside et Qt Designer


Fichiers .ui et utilisation avec Python

Nous avons vu précedemment comment concevoir graphiquement des fenêtres dans l'outil Qt Designer, puis comment les exploiter dans notre code Python. Nous avons d'abord utilisé la classe QUiLoader et récupéré un objet de type QWidget (généralement de type QMainWindow précisément).

from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QApplication

def button_slot():
    """Fonction utilisée comme slot."""
    pass

if __name__ == '__main__':
    app = QApplication()
    window = QUiLoader().load("file.ui")
    button = window.button
    button.clicked.connect(button_slot)
    window.show()
    ...
    app.exec()

Problème de l'approche "non objet"

Cette approche simple ne permet malheureusement pas de profiter de certaines fonctionnalités essentielles. Par exemple, il n'est pas possible de définir des slots via de simples fonctions dans lesquels il serait possible de retrouver un widget qui a généré un signal.

La raison principale à cette catégorie de problèmes provient du fait que l'application Qt est gérée via l'objet QApplication dans un thread distinct. Ce thread n'est pas en mesure de transmettre certaines références au processus principal de votre programme, notamment les références d'objets générant un signal.


Le seul moyen correct de procéder (assez mal documenté) afin que votre code gérant vos widgets soit connecté au thread de l'application Qt : Coder la gestion de votre fenêtre dans une classe héritant au moins d'une classe de la bibliothèque Qt (ex. QObject). Hériter d'une telle classe vous offre d'ailleurs une méthode essentielle pour retrouver une référence d'objet ayant généré un signal : sender()


Voici un exemple de code correct important une conception graphique d'un fichier .ui :

from PySide6.QtCore import QObject, Slot
from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QWidget

class WindowManager(QObject):
    """Classe gérant l'interface graphique et contenant des slots."""
    window: QMainWindow | QWidget = None
    button: QPushButton = None
  
    def __init__(self, *args, **kwargs):
        # Ligne nécessaire pour exécuter l'initiation du QObject
        super().__init__(*args, **kwargs)
        self.window = QUiLoader().load("fichier.ui")
        self.button = getattr(self.window, "button")
        # Configurer le clic sur le bouton peut être configuré dans Designer
        self.button.clicked.connect(self.button_clicked)
    
    @Slot()  # marquer correctement la méthode comme slot
    def button_clicked(self):
        """Slot du clic sur le bouton."""
        print(self.sender())
        
if __name__ == '__main__':
    application = QApplication()
    manager = WindowManager()
    manager.window.show()
    application.exec()

Dans l'exemple précédent, plusieurs éléments importants ont été rigoureusement respectés :

  • La classe de gestion de l'interface et des slots hérite de QObject au moins;
  • les slots sont décorés par la classe Slot, qui possède une méthode __call__ renvoyant un décorateur (parenthèses nécessaires);

Utiliser des widgets personnalisés dans Designer

Supposons que vous avez rédigé du code pour créer votre propre widget (soit personnellement dessiné soit composé d'autres sous-widgets). Vous souhaitez utiliser Qt Designer pour concevoir votre interface, faisant usage dudit widget.

Malheureusement pour vous, seuls les widgets standard proposés par la bibliothèque Qt seront disponibles dans la boîte à outils de Qt Designer. Heureusement, il est possible de personnaliser votre conception pour intégrer vos propres classes de widgets. Pour cela vous devez insérer dans l'interface un widget duquel hérite votre classe personnalisée (ex. QFrame) puis le "promouvoir".


Pour cela, sélectionnez votre widget dans l'interface d'aperçu ou dans l'explorateur d'objet avec un clic droit. Cliquez ensuite sur l'option Promouvoir en…. Une boîte de dialogue listant les widgets déjà promus s'affichera et vous proposera de promouvoir le widget que vous venez de sélectionner.

Promotion de widget


Vous devez sélectionner la classe de widget de base (probablement celle déjà utilisée pour le widget à promouvoir), puis indiquer le nom de la classe de widget à utiliser à l'exécution. Le nom du fichier d'en-tête n'est utilisé que pour le langage C++, donc vous pouvez y saisir un point (.).


Une fois le fichier .ui regénéré, il vous faudra configurer votre objet QUiLoader pour y enregistrer les classes de widgets personnalisées :

from PySide6.QtUiTools import QUiLoader
from mymodule import MyWidgetClass

loader = QUiLoader()
# Register custom widget class so that the promoted widget works.
loader.registerCustomWidget(MyWidgetClass)
widget = loader.load("fichier.ui")

Au chargement du fichier XML, les références du nom de classe généreront correctement les instances du type approprié. Notez que si votre classe de widget définit des propriétés supplémentaires par rapport à la classe dont elle hérite, vous pouvez les ajouter et les initialiser dans le panneau de l'éditeur de propriétés de Qt Designer.


CSS dans les widgets

Propriétés CSS

Appliquer correctement son CSS

Appliquer depuis un fichier

Ressources

Créer une ressource

Compiler une ressource