Ce TD fait suite au TD1. Dans le TD1, nous avons vu comment développer une application selon le patron de conception "Modèle - Vue - Contrôleur" (MVC).
Nous allons programmer une interface graphique avec la librairie appJar (voir aussi S5-POO)
L'écriture d'une interface graphique permet de mettre en œuvre les principes de la programmation événementielle:
Dans le cadre du patron MVC, les informations affichées dans l'interface (le contenu des widgets) sont paramétrées par les objets du modèle. On a typiquement le cycle suivant :
Ouvrez Pycharm et reprenez le projet du TD1.
Pour rappel, le programme sert à gérer une petite animalerie (constituée de rongeurs divers…). Les animaux sont décrits dans le fichier animal.json
et les équipements (litière, roue, mangeoire,…) dans le fichier équipement.json
.
vue.py
from appJar import gui
app = gui()
Le but est de construire une interface très simple:
Le premier bandeau (rose saumon) peut être défini à l'aide des commandes suivantes :
app.addLabel("en-tête", "Bienvenue à l'animalerie!") app.setLabelBg("en-tête", "salmon") app.setLabelFg("en-tête", "white")
Label
est ajouté à l'application. "en-tête"
app.setXXX…
indexé par "en-tête"
.Pour tester le rendu, il suffit d'ajouter la commande:
app.go()
et d'exécuter vue.py
.
Définissez un deuxième bandeau de couleur grise ("gray"
) affichant le texte "Tableau de bord"
en blanc, et exécutez la vue pour vérifier l'affichage
Pour afficher l'état des animaux, il faut à présent consulter le modèle.
import modele
liste_animaux = ['Tic', 'Tac', 'Totoro', 'Patrick', 'Pocahontas']
Pour chaque animal de la liste :
La deuxième partie de la vue est constituée de deux listes à choix multiples pour choisir l'action à effectuer :
Le bouton Go
permet de lancer l'exécution, via un appel au contrôleur.
Dans l'exemple présenté, les listes à choix multiples sont réalisées par des widgets de type "RadioButton" permettant de fixer une valeur. Nous avons deux valeurs à définir :
getRadioButton(index)
a
de la liste des animaux, initialiser un bouton radio indexé par "id_animal"
:app.addRadioButton("id_animal", a)
c
de la liste des actions initialisez un bouton radio indexé par "action"
:app.addRadioButton("action", c)
On ajoute à présent le bouton d'action qui permet d'exécuter les actions définies dans le contrôleur:
On commence par importer le contrôleur:
import controleur
Exemple :
controleur.nourrir(id_animal)
a pour effet de modifier dans le modèle l'état de l'animal choisi :
Dans l'interface, un bouton (Button) permet de lancer l'exécution d'une fonction selon la syntaxe:
app.addButton("go", press)
Définir la fonction :
def press(act): ...
qui exécute une action du contrôleur selon les deux valeurs :
app.getRadioButton("action")
: le nom de l'actionapp.getRadioButton("id_animal")
: l'identifiant de l'animal
ainsi si l'action vaut "nourrir"
alors il faut exécuter :
controleur.nourrir(app.getRadioButton("id_animal"))
etc.
Attention XXX n'a pas faim
doit en effet s'afficher dans la console.Lorsqu'elles sont valides, les actions modifient le contenu du modèle, mais ces changements ne sont pas visibles au niveau de l'interface. Pour répercuter le résultat de l'action dans la vue, il faut donc mettre à jour le widgets correspondant à l'affichage de l'état des animaux (le "tableau de bord").
app.setLabel(id_animal, ...)
press()
Il est préférable lorsque l'action n'est pas valide d'afficher le message d'erreur dans une fenêtre pop-up du type :
Les fenêtre à message sont exécutées à l'aide d'une commande:
app.warningBox("", texte)
"Félicitations, Totoro a rejoint le nid et est maintenant endormi."
)infoBox
et les actions invalides dans des warningBox
Il est possible d'améliorer le rendu visuel de la vue en utilisant un positionnement tabulaire pour les widgets. Vous êtes invités à consulter la documentation pour obtenir un rendu du type:
app.setLabelBg(label, "lavender")
app.setLabelAlign(label, "left")