• Aucun résultat trouvé

Intégration de widgets composites dans une application synthèse

Dans le document Chapitre 1 : Penser comme un programmeur (Page 170-174)

objet.méthode(arguments)

Chapitre 10 : Approfondir les structures de données

13.4 Intégration de widgets composites dans une application synthèse

Dans les exercices précédents, nous avons construit deux nouvelles classes de widgets : le widget OscilloGraphe(), canevas spécialisé pour le dessin de sinusoïdes, et le widget ChoixVibra(), panneau de contrôle à trois curseurs permettant de choisir les paramètres d'une vibration.

Ces widgets sont désormais disponibles dans les modules oscillo.py et curseurs.py49

Nous allons à présent les utiliser dans une application synthèse, qui pourrait illustrer votre cours de physique : un widget OscilloGraphe() y affiche un, deux, ou trois graphiques superposés, de couleurs différentes, chacun d'entre eux étant soumis au contrôle d'un widget ChoixVibra() :

Le script correspondant est reproduit ci-après.

Nous attirons votre attention sur la technique mise en oeuvre pour provoquer un rafraîchissement de l'affichage dans le canevas, chaque fois que l'utilisateur effectue une action quelconque au niveau de l'un des panneaux de contrôle.

Rappelez-vous que les applications destinées à fonctionner dans une interface graphique doivent être conçues comme des "programmes pilotés par les événements" (voir page 80).

49 Il va de soi que nous pourrions rassembler toutes les classes que nous construisons dans un seul module.

En préparant cet exemple, nous avons arbitrairement décidé que l'affichage des graphiques serait déclenché par un événement particulier, tout à fait similaire à ceux que génère le système d'exploitation lorsque l'utilisateur accomplit une action quelconque. Dans la gamme (très étendue) d'événements possibles, nous en avons choisi un qui ne risque guère d'être utilisé pour d'autres raisons, pendant que notre application fonctionne : la combinaison de touches <Maj-Ctrl-Z>.

Lorsque nous avons construit la classe de widgets ChoixVibra(), nous y avons donc incorporé les instructions nécessaires pour que de tels événements soient générés, chaque fois que l'utilisateur actionne l'un des curseurs ou modifie l'état de la case à cocher. Nous allons à présent définir le gestionnaire de cet événement et l'inclure dans notre nouvelle classe : nous l'appellerons montreCourbes() et il se chargera de rafraîchir l'affichage. Étant donné que l'événement concerné est du type <enfoncement d'une touche>, nous devrons cependant le détecter au niveau de la fenêtre principale de l'application.

1. from oscillo import * 2. from curseurs import * 3.

4. class ShowVibra(Frame):

5. """Démonstration de mouvements vibratoires harmoniques"""

6. def __init__(self, boss =None): 14. self.gra.configure(bg ='white', bd=2, relief=SOLID) 15. self.gra.pack(side =TOP, pady=5) 23. self.master.bind('<Control-Z>', self.montreCourbes)

24. self.master.title('Mouvements vibratoires harmoniques') 25. self.pack()

26.

27. def montreCourbes(self, event):

28. """(Ré)Affichage des trois graphiques élongation/temps"""

29. for i in range(3):

45. ShowVibra().mainloop()

Commentaires :

Lignes 1-2 : Nous pouvons nous passer d'importer le module Tkinter : chacun de ces deux modules s'en charge déjà.

Ligne 4 : Puisque nous commençons à connaître les bonnes techniques, nous décidons de construire l'application elle-même sous la forme d'une classe, dérivée de la classe Frame() : ainsi nous pourrons plus tard l'intégrer toute entière dans d'autres projets, si le coeur nous en dit.

Lignes 8-10 : Définition de quelques variables d'instance (3 listes) : les trois courbes tracées seront des objets graphiques, dont les couleurs sont pré-définies dans la liste self.couleur. Nous devons préparer également une liste self.trace pour mémoriser les références de ces objets graphiques, ainsi qu'une liste self.controle pour mémoriser les références des trois panneaux de contrôle.

Lignes 13 à 15 : Instanciation du widget d'affichage. Etant donné que la classe OscilloGraphe() a été obtenue par dérivation de la classe Canvas(), il est toujours possible de configurer ce widget en redéfinissant les options spécifiques de cette classe (ligne 13).

Lignes 18 à 20 : Pour instancier les trois widgets "panneau de contrôle", on utilise une boucle.

Leurs références sont mémorisées dans la liste self.controle préparée à la ligne 10. Ces panneaux de contrôle sont instanciés comme esclaves du présent widget, par l'intermédiaire du paramètre self. Un second paramètre leur transmet la couleur du tracé à contrôler.

Lignes 23-24 : Au moment de son instanciation, chaque widget Tkinter reçoit automatiquement un attribut master qui contient la référence de la fenêtre principale de l'application. Cet attribut se révèle particulièrement utile si la fenêtre principale a été instanciée implicitement par Tkinter, comme c'est le cas ici.

Rappelons en effet que lorsque nous construisons une application en instanciant directement un widget tel que Frame, par exemple (c'est ce que nous avons fait à la ligne 4), Tkinter instancie automatiquement une fenêtre maîtresse pour ce widget (un objet de la classe Tk()).

Comme cet objet a été créé automatiquement, nous ne disposons d'aucune référence dans notre code pour y accéder, si ce n'est par l'intermédiaire de l'attribut master que Tkinter associe donc automatiquement à chaque widget.

Nous nous servons de cette référence pour redéfinir le bandeau-titre de la fenêtre principale (à la ligne 24), et pour y attacher un gestionnaire d'événement (à la ligne 23).

Lignes 27 à 40 : La méthode décrite ici est le gestionnaire des événements <Maj-Ctrl-Z>

spécifiquement déclenchés par nos widgets ChoixVibra() (ou "panneaux de contrôle"), chaque fois que l'utilisateur exerce une action sur un curseur ou une case à cocher. Dans tous les cas, les graphiques éventuellement présents sont d'abord effacés (ligne 28) à l'aide de la méthode delete() : le widget OscilloGraphe() a hérité cette méthode de sa classe parente Canvas().

Ensuite, de nouvelles courbes sont retracées, pour chacun des panneaux de contrôle dont on a coché la case "Afficher". Chacun des objets ainsi dessinés dans le canevas possède un numéro de référence, renvoyé par la méthode traceCourbe() de notre widget OscilloGraphe().

Les numéros de référence de nos dessins sont mémorisés dans la liste self.trace.

Ils permettent d'effacer individuellement chacun d'entre eux (cfr. instruction de la ligne 28).

Lignes 38-40 : Les valeurs de fréquence, phase & amplitude que l'on transmet à la méthode traceCourbe() sont les attributs d'instance correspondants de chacun des trois panneaux de contrôle, eux-mêmes mémorisés dans la liste self.controle. Nous pouvons récupérer ces attributs en utilisant la qualification des noms par points.

Exercices :

e 155. Modifiez le script, de telle manière que chacun des panneaux de contrôle soit entouré d'une bordure de la couleur du tracé correspondant.

e 156. Modifiez le script, de manière à faire apparaître et contrôler 4 graphiques au lieu de trois.

Pour la couleur du quatrième graphique, choisissez par exemple : 'blue', 'navy', 'maroon', ...

e 157. Aux lignes 33-35, nous récupérons les valeurs des fréquence, phase & amplitude choisies par l'utilisateur sur chacun des trois panneaux de contrôle, en accédant directement aux attributs d'instance correspondants. Python autorise ce raccourci - et c'est bien pratique – mais cette technique enfreint l'une des recommandations des théoriciens de la "programmation orientée objet", qui préconisent que l'accès aux propriétés des objets soit toujours pris en charge par des méthodes spécifiques.

Pour respecter cette recommandation, ajoutez à la classe ChoixVibra() une méthode supplémentaire que vous appellerez valeurs(), et qui retournera un tuple contenant les valeurs de la fréquence, la phase et l'amplitude choisies. Les lignes 33 à 35 du présent script pourront alors être remplacées par quelque chose comme :

freq, phase, ampl = self.control[i].valeurs() n

e 158. Écrivez une petite application qui fait apparaître une fenêtre avec un canevas et un widget curseur (Scale). Dans le canevas, dessinez un cercle, dont l'utilisateur pourra faire varier la taille à l'aide du curseur.

Chapitre 14 : Et pour quelques widgets de plus ...

Les pages qui suivent contiennent des indications et et des exemples complémentaires qui pourront vous être utiles pour le développement de vos projets personnels. Il ne s'agit évidemment pas d'une documentation de référence complète sur Tkinter. Pour en savoir plus, vous devrez tôt ou tard consulter des ouvrages spécialisés, comme par exemple l'excellent Python and Tkinter programming de John E. Grayson, dont vous trouverez la référence complète à la page 8.

Dans le document Chapitre 1 : Penser comme un programmeur (Page 170-174)