Accès rapide :
La vidéo
Petit préalable : Qt et la PEP 8
Deux approches distinctes
Exemple simple avec l'approche traditionnelle.
Exemple simple avec l'approche QtQuick/QML.
Quelle approche choisir, QtWidgets ou QtQuick/QML ?
Ressources complémentaires
Cette nouvelle vidéo vous présente les deux approches de développement d'interfaces graphiques proposées par Qt : l'approche Widget et l'approche QtQuick/Qml.
Ceux qui ont suivit mon tutoriel sur le langage de programmation Python, savent que j'accorde une importance particulière à la fameuse PEP 8 - « Style Guide for Python Code » : il s'agit d'un ensemble de règles de bonne conduite quand on code en Python. On peut diviser ces règles en deux parties : les règles de formatage et les règles de nommage.
Mais, nous avons un petit dilemme : Qt n'est pas une librairie originellement développée en Python. Par rappel, Qt est développée en C++. Du code cette librairie ne respecte pas les mêmes règles de nommage que Python. Du coup, que fait-on ? Quand on code une application Qt, on respecte les mêmes conventions que Qt ou on reste sur la PEP 8 ? La question est légitime et je ne prétendrais même avoir la bonne réponse à cette question.
Par contre, dans le cadre de ce tutoriel, j'ai pris une décision : comme la plupart des exemples de codes que je vais vous proposer ne contiendront que du code Qt, je vais m'aligner sur la convention Qt (et non pas la PEP 8) : cela me permettra de vous présenter des codes plus uniformes, notamment sur les noms des méthodes.
Du coup ce choix soulève un autre problème : PyCharm génère des warnings quand les règles de la PEP 8 sont enfreintes ! Heureusement cet IDE permet de désactiver la vérification sur les règles de nommage sans désactiver la vérification des règles de formatage. Je vous propose donc de reconfigurer PyCharm dans le cadre de ce tutoriel.
Veuillez ouvrir le menu « File » et activer cliquez sur « Settings » : la boîte de dialogue des préférences de PyCharm doit s'ouvrir. Dans le champ de recherche en haut et à gauche, veuillez saisir PEP8 pour réduire le nombre de sections de configuration affichées. Puis dans « Inspections » décochez les vérifications sur les conventions de nommage, comme le montre la capture d'écran ci-dessous.
Il existe deux approches différentes pour coder une application graphique Qt.
L'approche traditionnelle : c'est la première qui a été proposée et elle repose uniquement sur de la programmation. Il n'y a pas de séparation entre la notion de vue et les gestionnaires d'événements : tout est codé en Python.
L'approche QtQuick/QML : l'interface n'est plus décrite en Python (ou en C++), mais avec un langage déclaratif, le fameux QML (Qt Modeling Language). Le langage QML peut contenir du code JavaScript pour la gestion des événements.
Donc, si on utilise l'approche traditionnelle, l'interface graphique est entièrement constituée par code Python.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
from PySide6.QtGui import QIcon from PySide6.QtWidgets import QMainWindow, QPushButton, QApplication, QWidget import sys # On définit une classe pour notre nouvelle fenêtre. class MyWindow(QMainWindow): # Le constructeur de notre classe de fenêtre. def __init__(self): # On initialise la fenêtre, notamment en rappelant le constructeur parent. super().__init__() self.setWindowTitle("Ma première fenêtre Qt avec Python") self.setWindowIcon(QIcon("icon.png")) self.resize(400, 300) # On crée un widget représentant la zone centrale de la fenêtre. centralWidget = QWidget() # On y ajoute un premier bouton. self.__button1 = QPushButton("Premier bouton", centralWidget) self.__button1.setGeometry(20, 20, 200, 35) self.__button1.clicked.connect(self.doSomething) # On fait de même pour un second bouton. self.__button2 = QPushButton("Second bouton", centralWidget) self.__button2.setGeometry(20, 60, 200, 35) self.__button2.clicked.connect(self.doSomething) # On injecte le composant en tant que "widget central". self.setCentralWidget(centralWidget) # Un gestionnaire d'événements (voir les connexions ci-dessus). def doSomething(self): print(self.sender().text(), "cliqué") if __name__ == "__main__": # On crée un objet représentant l'application Qt. app = QApplication(sys.argv) # On crée une instance de notre fenêtre et on l'affiche. myWindow = MyWindow() myWindow.show() # On lance le système Qt. sys.exit(app.exec()) |
Et voici la fenêtre affichée par l'exemple ci-dessus.
L'approche QtQuick propose donc un langage déclaratif, le QML, pour définir le contenu de votre fenêtre. QML Signifie Qt Modeling Language. Voici un exemple, assez simple, de fichier QML : il définit une fenêtre et positionne un bouton en son centre.
import QtQuick import QtQuick.Controls ApplicationWindow { title: "Ma première fenêtre Qt/QML avec Python" width: 640 height: 480 visible: true Button { text: "Push Me" anchors.centerIn: parent width: 200 } }
Et voici maintenant un exemple de code Python permettant de charger et d'afficher votre fenêtre QML.
1 2 3 4 5 6 7 8 9 10 11 |
import sys from PySide6.QtQml import QQmlApplicationEngine from PySide6.QtGui import QGuiApplication, QIcon if __name__ == "__main__": app = QGuiApplication(sys.argv) app.setWindowIcon(QIcon("icon.png")) engine = QQmlApplicationEngine() engine.load("Hello.qml") sys.exit(app.exec()) |
Voila une question à laquelle il n'est pas simple de répondre. Déjà, d'une personne à une autre, je pense que les réponses pourront être différentes, donc c'est pas gagné ! ;-)
Personnellement, je propose les orientations suivantes :
Vous souhaitez développer une application qui devra être déployée uniquement sur un poste « Desktop ». Elle devra afficher des composants graphiques classiques pour collecter les données de l'utilisateur. Enfin, vous n'avez pas de contraintes fortes sur les temps de pixellisation. Dans cette situation, je recommande peut-être l'approche traditionnelle.
Vous devez développer une application qui devra s'exécuter sur un périphérique tactile (Smart phone ou tablette). Dans ce cas, l'approche traditionnelle n'est pas recommandée : les éléments classiques d'IHM (barre de menu, ...) sont peu adaptés à un environnement tactile. Je vous conseille donc l'approche QtQuick/QML.
Je vous propose aussi de réfléchir aux pistes suivantes :
Un script QML sera toujours plus lent qu'un code équivalent codé en C/C++ : si vous avez besoin de coder des traitements complexes (traitement du signal, ...), privilégiez du code C/C++ (n'oubliez pas que Qt est avant tout prévu pour fonctionner avec du C++). Python peut lui aussi s'avérer plus rapide que des scripts QML sur certains types de traitements et notamment avec l'utilisation des librairie NumPy et SciPy (c'est logique, ces librairies sont principalement codées en C et Fortran).
QtQuick s'appuie sur un support natif GPU (Graphics Processing Unit), ce qui n'est pas le cas de l'approche QtWidgets qui n'exploite que le CPU. Si vous avez à produire des tracés complexes et que vous souhaitiez avoir de la fluidité, privilégiez l'approche QtQuick/QML.
Notez que j'ai aussi écrit plusieurs supports de cours sur la mise en oeuvre d'applications graphiques avec Qt. Certes, les deux derniers sont pour C++, mais celui sur QML contient beaucoup d'informations applicables à un développement Python (toutes les informations relatives à la syntaxe QML).
Améliorations / Corrections
Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.
Emplacement :
Description des améliorations :