Sujet

Note préliminaire : il est préférable de lire toutes les "étapes" en entier (en particulier les notes ou remarques) avant de commencer ce TP.

Exercice 1 : dessiner un bouton

1e Etape: Démarrage

Créer un fichier Button.py avec votre éditeur de texte préféré

Créer une fonction main(args) qui sera appelé à partir du point d'entrée du programme (if __name__ == "__main__":)

La méthode main doit instancier une QApplication, instancier une QMainWindow, afficher l'instance de QMainWindow, et executer la QApplication

2e Etape: Classe CanvasButton

Définir une classe CanvasButton qui hérite de QWidget. Dans la méthode main, instancier un objet de type CanvasButton et le définir comme centralWidget de l'instance de QMainWindow.

Définir comme variables d'instance de CanvasButton une variable bbox de type QRect qui décrira la bounding box du futur bouton que votre classe va dessiner (initialisez cette variable avec des dimensions arbitraires). Définir comme variable de classe une varible defaultCol de type QColor.

Dans la classe CanvasButton, surcharger les méthodes mouseMoveEvent, mousePressEvent et mouseReleaseEvent qui sont héritées de la classe QWidget (allez voir la documentation). Assurez-vous que ces méthodes sont bien appelées quand les évènements surviennent (par exemple avec des print().

Surcharger la méthode paintEvent héritée de QWidget pour qu'elle dessine une ellipse de couleur DefaultCol qui a rect comme BoundingBox. Dans les étapes suivantes, nous allons faire en sorte que cette ellipse se comporte comme un bouton cliquable.

Définir une méthode cursorOnEllipse(self, point) qui verifie si un point est contenu par lellipse.

Définir une variable d'instance nommée cursorOver et de type booléen et modifier la méthode mouseMoveEvent pour qu'elle mette à jour la valeur de cursorOver à True quand le curseur survole l'ellipse, et à False sinon.

3e Etape: Classe ButtonModel

Créer un fichier ButtonModel et y déclarer une classe du même nom et y définir les 4 variables de classe suivantes: idle, hover, pressIn et pressOut auxquelles vous attriburez des valeurs entières arbitraires. Définir une variable d'instance state dans le constructeur de la classe et l'initialiser à idle.

L'objet ButtonModel a pour objectif de spécifier dans quel état va se trouver le bouton (l'ellipse) à un instant t. Ce modèle va correspondre à la machine à état suivante:

Définir une méthode pour chaque transition présente (vous devrez définir 4 méthodes) dans la machine à état et faire en sorte que la valeur de state change en fonction de la transition et de l'état courant.

Définir une méthode action qui sera appelée lorsque la machine à état traverse l'état Action et fera un print dans la console

4e Etape: synchroniser ButtonModel et CanvasButton

Ajouter une variable d'instance de type ButtonModel dans la classe CanvasButton

Modifier les méthodes de gestion de évènements souris en sorte qu'elles appellent les méthodes correspondant aux transitions de l'objet ButtonModel. Ainsi, la variable d'self.state de l'instance de l'objet ButtonModel doit à tout instant correspondre à l'état actuel du bouton

Définir deux variables de classes hoverCol et pressCol de type QColor qui vont correspondre aux différentes couleurs adoptées par le bouton.

Modifier la méthode paintEvent pour que le bouton adopte la bonne couleur et au final le bon comportement, comme illustré ci-dessous:

Exercice 2 : Zone de dessin

1e Etape: Créer un nouveau projet affichant une zone de dessin

Créer un fichier CanvasDessin.py dans lequel vous déclarez et implémentez une classe CanvasDessin. Pour l'instant cette classe ne fera pas grand chose : elle doit juste hériter de QWidget. La taille par défaut d'un QWidget étant nulle (celle-ci étant calculée à partir des enfants qu'il contient), utiliser la méthode setMinimumSize() pour imposer une taille adéquate. Créer un nouveau fichier Dessin.py dans lequel vous déclarerez une fonction main(args) qui sera appelé à partir du point d'entrée du programme (if __name__ == "__main__":).

Créez également dans Dessin.py une classe Dessin qui hérite de QMainWindow et qui a comme variable d'instance un objet CanvasDessin qui lui est passé comme zone centrale.

À l'image des exercices précédents, modifier la méthode main pour qu'elle instancie une application Qt, instancie un Dessin et l'affiche. Tester.

2e Etape: créer une classe Trace

Creer une classe Trace dans un fichier Trace.py, qui a une variable d'instance points (de type list), width (de type int) et color (de type Qcolor). Écrire le constructeur de la classe Trace, qui permettra de spécifier en paramètre les valeurs initiales de width et une color.

3e Etape: dessiner un tracé interactivement

Modifier la classe zone de dessin de telle sorte que l'on puisse interactivement y dessiner des tracés (l'événement press commence le segment, les évènements drag le poursuivent, et le release le termine).

Pour cela, il faudra définir une variable d'instance de type list qui stockera les tracés (qui seront des objets de type Trace) effectués à la souris. Il faudra également re-implémenter la méthode paintEvent de la classe CanvasDessin pour qu'elle parcours la liste des Traces et les dessine à l'aide d'un objet QPainterPath.

4e Etape: spécifier des attributs graphiques

Rajouter à la classe CanvasDessin des variables d'instance et des fonctions permettant de modifier la couleur et l'épaisseur des prochains traits qui seront dessinés.

5e Etape: choisir interactivement les attributs graphiques

Modifiez l'interface graphique (normalement créée par la classe MainWindow ou similaire, pas par la classe de la zone de dessin) de telle sorte que l'on puisse régler interactivement les paramètres définis à la question précédente. Pour cela, ajouter une toolbar à la classe Dessin.

Pour la couleur du tracé, ajoutez à la toolbar une QAction qui ouvre un QColorDialog et recupère la valeur choisie par l'utilisateur pour la définir comme couleur à utiliser pour les tracés à venir. Pour l'epaisseur du tracé, ajoutez à la toolbar un QSlider. Enfin, ajoutez également un QPushButton qui permette d'effacer complètement le contenu du canvas.

6e Etape: mettre à jour l'affichage du bouton qui permet de choisir la couleur

En l'état actuel, l'action qui permet de spécifier la couleur du prochain tracé ne suggère pas cette couleur à l'utilisateur. Il lui est donc impossible de savoir de quelle couleur sera le tracé avant de l'avoir effectivement dessiné sur le canvas.

Modifier votre programme pour que l'icone associée à l'action qui permet de choisir la couleur affiche la couleur courante. Pour cela, vous pourrez instancier un objet de type QPixMap et utiliser la methode fill() pour remplir cette QPixMap d'une couleur donnée. Vous pourrez ensuite instancier un objet QIcon avec cette instance de QPixMap pour faire en sorte que la toolbar suggère en permanence la couleur courante.