Modèle-Vue-Contrôleur (MVC) et PyQt
Introduction
Les chapitres précédents nous ont permis de réaliser un rapide inventaire des principaux widgets utilisables en PyQt, puis de ceux qui permettent de mettre en place la disposition des éléments graphiques dans une fenêtre. Nous avons également vu au cours du chapitre précédent la gestion des évènements en PyQt.
Nous possédons donc tous les outils pour développer nos premières applications en PyQt. Ce sera donc le propos du présent chapitre avec au programme le développement d’une calculatrice, puis celui de petites applications de traitement de texte.
Nous allons préalablement étudier un élément d’architecture qui va s’avérer très utile : le paradigme Modèle-Vue-Contrôleur (MVC), qui permet d’organiser de façon claire les applications développées en séparant l’apparence (la vue), le traitement (le contrôleur) et le modèle (les données).
Le Modèle-Vue-Contrôleur (MVC)
1. Introduction
Jusqu’à maintenant, nous nous sommes concentrés sur la découverte du framework PyQt sans nous préoccuper plus avant de considérations relatives à l’architecture générale d’une application. On entend par architecture la manière d’organiser le code pour qu’il soit le plus clair, le plus maintenable et évolutif possible, y compris par une tierce personne. Le présent chapitre est destiné à développer nos premières applications réalistes en PyQt. C’est donc le moment idéal pour introduire le paradigme Modèle-Vue-Contrôleur (MVC), qui constitue justement une bonne pratique en matière d’architecture dans de nombreux langages en général, et en PyQt en particulier.
2. L’esprit du paradigme MVC
Dans ce paradigme d’architecture, on distingue trois grandes parties :
-
Le modèle (M) : contient les données impliquées dans l’application. Ce peut être concrètement un accès à une base de données, une structure de données, ou dans l’exemple de calculatrice, simplement la fonction en charge d’évaluer le résultat du calcul. Le modèle inclut les données telles qu’elles sont ensuite affichées dans la vue....
Développement d’une application de calculatrice
1. Introduction
Entrons dans le vif du sujet et commençons par développer une calculatrice. Voici le bref cahier des charges : on souhaite avoir les quatre opérations élémentaires, les chiffres 0 à 9 ainsi que la touche « 00 », bien pratique. On désire également avoir les parenthèses ouvrantes et fermantes. Enfin, on veut pouvoir manipuler des nombres à virgule. Ainsi nous serons en capacité d’écrire une expression comme :
(5 + 3.5) * 12.25 / 3
Lorsque l’utilisateur clique sur « = », l’expression est évaluée et affiche le résultat. Bien entendu, dans ce chapitre, on cherche à avoir un respect du paradigme Modèle-Vue-Contrôleur autant que possible.
2. Analyse, architecture et codage
a. Développement de la vue
Ci-dessous, voici l’apparence de l’application calculatrice que nous cherchons à développer. Pour réaliser cet affichage simplement, on met en place un widget QMainWindow qui inclut un simple QWidget qui lui-même contient :
-
un widget QLineEdit pour afficher l’expression et pour afficher le résultat de son évaluation ;
-
vingt widgets QPushButton.
Apparence de la calculatrice à développer
On crée donc une classe Calculatrice qui correspondra à la vue dans le paradigme MVC. On choisit de la faire hériter de QMainWindow.
On a donc ces premières lignes de code :
class Calculatrice(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Calculatrice")
self.setFixedSize(235, 235)
self.disposition = QVBoxLayout()
self._widget = Qwidget(self)
self.setCentralWidget(self._widget)
self._widget.setLayout(self.disposition)
Dans ce même initialiseur __init__, on appelle deux méthodes de classes : la première...
Développement d’une application Notepad
1. Introduction
Le but ici est de développer une application Notepad. Le cahier des charges (simplifié) est le suivant :
-
On peut éditer un petit texte.
-
Il est possible de le sauvegarder dans un fichier. On peut également ouvrir le contenu d’un fichier préalablement sauvegardé et l’afficher.
-
L’utilisateur a la possibilité de sauvegarder un fichier sous un autre nom que celui préalablement chargé.
-
On peut imprimer le texte à l’écran.
-
On peut procéder à des actions défaire (undo) et refaire (redo).
-
Il est possible de procéder à des actions de copier, couper, coller.
Les actions précitées sont disponibles dans un menu.
-
Ces mêmes actions sont également disponibles dans une barre d’outils (toolbar).
L’application ressemble à la copie d’écran suivante :
Vue de l’application Notepad
On peut voir également les menus déroulants contenant les diverses actions :
Menu déroulant « Édition » de l’application Notepad
2. Programmation de l’application
Les widgets PyQt sont suffisamment intégrés pour qu’il n’y ait finalement pas grand-chose à faire, si ce n’est justement procéder à une intégration judicieuse.
De manière habituelle, on définit notre point d’entrée, dans lequel on instancie notre interface utilisateur.
if __name__ == '__main__':
app = Qapplication(sys.argv)
app.setApplicationName("Le petit éditeur de texte")
window = EditeurDeTexte()
app.exec_()
La classe de référence de notre programme s’appelle EditeurDeTexte. Cette dernière hérite de la classe PyQt QMainWindow. On définit alors l’initialiseur __init__. On utilise un contrôle d’agencement vertical QVBoxLayout dans lequel on dispose une barre de statut (QStatusBar).
class EditeurDeTexte(QMainWindow):
def __init__(self, *args, **kwargs):
super(EditeurDeTexte, self).__init__(*args, **kwargs) ...
Développement d’une application d’éditeur de texte enrichi
1. Introduction
Voici ci-dessous l’apparence attendue de l’application, alors que l’utilisateur vient de cliquer sur l’un des boutons de choix de couleur, que ce soit une couleur de police ou une couleur de fond). Ce clic ouvre ainsi le dialogue de choix de couleur suivant :
Application d’édition de texte enrichi
Le cahier des charges de cette application se définit selon les points suivants :
-
Un élément de menu « Fichier » doit permettre de créer un nouveau document, de le sauver et d’ouvrir un document existant.
-
On veut pouvoir choisir la police et la taille de celle-ci.
-
On veut pouvoir sélectionner la couleur de la police ainsi que la couleur de fond pour un fragment de texte donné.
-
On veut pouvoir mettre en italique, mettre en gras, souligner et barrer le texte.
-
On veut enfin pouvoir aligner à gauche, au centre, à droite ou en justifié un élément de texte.
Nous commençons donc par rassembler des icônes pour chacune des actions incluses dans notre barre d’outils.
Dans cet exemple, nous choisissons de nommer les différentes variables et fonctions en anglais.
2. Programmation de l’application
On définit les imports suivants :
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
Notre point d’entrée est le suivant : il implique l’instanciation de la classe RichEditor qui hérite de QMainWindow.
if __name__ == "__main__":
app = Qapplication(sys.argv)
main = RichEditor()
main.show()
sys.exit(app.exec_())
La classe en question constitue le reste du code dans lequel on cherche à utiliser au mieux et au plus les widgets dédiés de PyQt.
On utilise les widgets ou classes PyQt suivantes :
-
QAction : utilisée pour les actions.
-
QFontComboBox : nous permet en quelques lignes d’implémenter une combobox proposant toutes les polices de caractères disponibles sur la machine.
-
QColorDialog : correspond au dialogue de sélection de couleurs utilisé pour la police et pour le fond. Là...
Conclusion du chapitre
Après avoir inventorié les principaux widgets de PyQt, appris à les disposer, et être montés en compétence sur la gestion des évènements en PyQt, nous pouvions consacrer ce chapitre à développer de premières applications. Outre l’usage de MVC dans la première application, il est intéressant de remarquer que la puissance de PyQt réside dans la richesse de ces widgets et dans leurs spécialisations. Ainsi, nous sommes en capacité d’écrire des applications relativement avancées, portables car développées en Python, en quelques dizaines de lignes de code seulement.