« Programmation Python/Classes et Interfaces graphiques » : différence entre les versions
Contenu supprimé Contenu ajouté
m JackPotte a déplacé la page Apprendre à programmer avec Python/Classes et Interfaces graphiques vers Programmation Python/Classes et Interfaces graphiques |
Aucun résumé des modifications |
||
Ligne 36 :
Au niveau principal du programme, nous nous contentons d'instancier un objet de la classe ainsi construite (aucune méthode de cet objet n'est activée de l'extérieur).
<source lang=python line>
class Application: #1
def __init__(self): #2
Ligne 106 :
from math import log10 # logarithmes en base 10 #68
f = Application() # instanciation de l'objet application #69
</
;Commentaires
Ligne 112 :
* Ligne 1 : La classe est définie sans référence à une classe parente (pas de parenthèses). Il s'agira donc d'une nouvelle classe indépendante.
* Lignes 2 à 14 : Le constructeur de la classe instancie les ''widgets'' nécessaires : pour améliorer la lisibilité du programme, on a placé l'instanciation du canevas (avec le dessin de la résistance) dans une méthode séparée <code>dessineResistance()</code>. Les boutons et le libellé ne sont pas mémorisés dans des variables, parce que l'on ne souhaite pas y faire référence ailleurs dans le programme. Le positionnement des ''widgets'' dans la fenêtre utilise la méthode <code>grid()</code>
* Lignes 15-17 : Le code des couleurs est mémorisé dans une simple liste.
Ligne 158 :
Nous allons à présent passer à la vitesse supérieure et réaliser une petite application sur la base de plusieurs classes, afin d'examiner ''comment différents objets peuvent s'échanger des informations par l'intermédiaire de leurs méthodes''. Nous allons également profiter de cet exercice pour vous montrer comment vous pouvez définir la classe principale de votre application graphique par ''dérivation'' d'une classe ''Tkinter'' préexistante, mettant ainsi à profit le mécanisme d'héritage.
Le projet développé ici très simple, mais il pourrait constituer une première étape dans la réalisation d'un logiciel de jeu : nous en fournissons d'ailleurs des exemples plus loin
[[Image:Apprendre à programmer avec Python 38.png|center]]
Ligne 172 :
;Implémentation
<source lang=python line>
</
;Commentaires
Ligne 233 :
* Lignes 3 à 5 : Nous projetons de dessiner une série de petits cercles. Cette petite fonction nous facilitera le travail en nous permettant de définir ces cercles à partir de leur centre et leur rayon.
* Lignes 7 à 13 : La classe principale de notre application est construite par dérivation de la classe de fenêtres <code>Tk()</code> importée du module Tkinter<ref>Nous verrons plus loin que ''Tkinter'' autorise également de construire la fenêtre principale d'une application par dérivation d'une classe de ''widget'' (le plus souvent, il s'agira d'un ''widget'' <code>Frame()</code>). La fenêtre englobant ce ''widget'' sera automatiquement ajoutée
* Lignes 15 à 20 : Ces lignes instancient les 4 objets-wagons, produits à partir de la classe correspondante. Ceci pourrait être programmé plus élégamment à l'aide d'une boucle et d'une liste, mais nous le laissons ainsi afin de ne pas alourdir inutilement les explications qui suivent. Nous voulons placer nos objets-wagons dans le canevas, à des emplacements bien précis : il nous faut donc transmettre quelques informations au constructeur de ces objets : au moins la référence du canevas, ainsi que les coordonnées souhaitées. Ces considérations nous font également entrevoir, que lorsque nous définirons la classe <code>Wagon()</code> un peu plus loin, nous devrons associer à sa méthode constructeur un nombre égal de paramètres pour réceptionner ces arguments.
Ligne 260 :
<ol>
<li>
<source lang=python>
from Tkinter import *
Ligne 327 :
Application().app.mainloop()
</
</li>
</ol>
Ligne 348 :
Veuillez donc encoder le script ci-dessous et le sauvegarder dans un fichier, auquel vous donnerez le nom <code>oscillo.py</code>. Vous réaliserez ainsi un véritable ''module'' contenant une classe (vous pourrez par la suite ajouter d'autres classes dans ce même module, si le cœur vous en dit).
<source lang=python line>
from Tkinter import *
from math import sin, pi
class OscilloGraphe(Canvas):
"Canevas spécialisé, pour dessiner des courbes élongation/temps"
def __init__(self, boss =None, larg=200, haut=150):
"Constructeur du graphique : axes et échelle horiz."
# construction du widget parent :
Canvas.__init__(self) # appel au constructeur
self.configure(width=larg, height=haut) # de la classe parente
self.larg, self.haut = larg, haut # mémorisation
self.create_line(10, haut/2, larg, haut/2, arrow=LAST) # axe X
# tracé d'une échelle avec 8 graduations :
pas = (larg-25)/8. # intervalles de l'échelle horizontale
for t in range(1, 9):
self.create_line(stx, haut/2-4, stx, haut/2+4)
def traceCourbe(self, freq=1, phase=0, ampl=10, coul='red'):
"tracé d'un graphique élongation/temps sur 1 seconde"
curve =[] # liste des coordonnées
pas = (self.larg-25)/1000. # l'échelle X correspond à 1 seconde
for t in range(0,1001,5): # que l'on divise en 1000 ms.
e = ampl*sin(2*pi*freq*t/1000 - phase)
curve.append((x,y))
#### Code pour tester la classe : ####
if __name__ == '__main__':
root = Tk()
gra = OscilloGraphe(root, 250, 180)
gra.pack()
gra.configure(bg ='ivory', bd =2, relief=SUNKEN)
gra.traceCourbe(2, 1.2, 10, 'purple')
root.mainloop()
</source>
Le niveau principal du script est constitué par les lignes 35 à 41.
Nous disposons ainsi d'un mécanisme intéressant, qui nous permet d'intégrer des instructions de test à l'intérieur des modules, même si ceux-ci sont destinés à être importés dans d'autres scripts.
Ligne 446 ⟶ 444 :
{{fin}}
Il est temps à présent que nous analysions la structure de la classe qui nous a permis d'instancier tous ces ''widgets''. Nous avons enregistré cette classe dans le module oscillo.py
;Cahier des charges
Ligne 462 ⟶ 460 :
* Ligne 6 : La méthode « constructeur » utilise 3 paramètres, qui sont tous optionnels puisque chacun d'entre eux possède une valeur par défaut. Le paramètre boss ne sert qu'à réceptionner la référence d'une fenêtre maîtresse éventuelle (voir exemples suivants). Les paramètres <code>larg</code> et <code>haut</code> (largeur et hauteur) servent à assigner des valeurs aux options <code>width</code> et <code>height</code> du canevas parent, au moment de l'instanciation.
* Lignes 9 et 10 : La première opération que doit accomplir le constructeur d'une classe dérivée, c'est activer le constructeur de sa classe parente. En effet : nous ne pouvons hériter toute la fonctionnalité de la classe parente, que si cette fonctionnalité a été effectivement mise en place.<br />Nous activons donc le constructeur de la classe <code>Canvas()</code> à la ligne 9 , et nous ajustons deux de ses options à la ligne 10. Notez au passage que nous pourrions condenser ces deux lignes en une seule, qui deviendrait en l'occurrence :
<pre>Canvas.__init__(self, width=larg, height=haut)</pre> Nous devons transmettre à ce constructeur la référence de l'instance présente (self) comme premier argument. * Ligne 11 : Il est nécessaire de mémoriser les paramètres <code>larg</code> et <code>haut</code> dans des variables d'instance, parce que nous devrons pouvoir y accéder aussi dans la méthode <code>traceCourbe()</code>.
Ligne 470 :
* Lignes 16 à 19 : Pour tracer l'échelle horizontale, on commence par réduire de 25 pixels la largeur disponible, de manière à ménager des espaces aux deux extrémités. On divise ensuite en 8 intervalles, que l'on visualise sous la forme de 8 petits traits verticaux.
* Ligne 21 : La méthode <code>traceCourbe()</code> pourra être invoquée avec quatre arguments. Chacun d'entre eux pourra éventuellement être omis, puisque chacun des paramètres correspondants possède une valeur par défaut. Il sera également possible de fournir les arguments dans n'importe quel ordre
* Lignes 23 à 31 : Pour le tracé de la courbe, la variable ''t'' prend successivement toutes les valeurs de 0 à 1000, et on calcule à chaque fois l'élongation ''e'' correspondante, à l'aide de la formule théorique (ligne 26). Les couples de valeurs ''t'' et ''e'' ainsi trouvées sont mises à l'échelle et transformées en coordonnées x, y aux lignes 27 & 28, puis accumulées dans la liste <code>curve</code>.
Ligne 516 :
Le petit script ci-dessous vous montre comment le paramétrer et l'utiliser dans une fenêtre :
<source lang=python>
from Tkinter import *
Ligne 531 :
root.mainloop()
</
Ces lignes ne nécessitent guère de commentaires.
Ligne 551 :
[[Image:Apprendre à programmer avec Python 44.png|center]]
<source lang=python line>
</
Ce panneau de contrôle permettra à vos utilisateurs de régler aisément la valeur des paramètres indiqués (fréquence, phase et amplitude), lesquels pourront alors servir à commander l'affichage de graphiques élongation/temps dans un ''widget'' de la classe <code>OscilloGraphe()</code> construite précédemment, comme nous le montrerons dans l'application de synthèse.
Ligne 631 :
<li>Lignes 26 à 40 : Les 4 ''widgets'' définis dans les lignes précédentes possèdent chacun une option <code>command</code>. Pour chacun d'eux, la méthode invoquée dans cette option command est différente : la case à cocher active la méthode <code>setCurve()</code>, le premier curseur active la méthode <code>setFrequency()</code>, le second curseur active la méthode <code>setPhase()</code>, et le troisième curseur active la méthode <code>setAmplitude()</code>. Remarquez bien au passage que l'option <code>command</code> des ''widgets'' <code>Scale</code> transmet un argument à la méthode associée (la position actuelle du curseur), alors que la même option <code>command</code> ne transmet rien dans le cas du ''widget'' <code>Checkbutton</code>.
Ces 4 méthodes (qui sont donc les gestionnaires des événements produits par la case à cocher et les trois curseurs) provoquent elles-mêmes chacune l'émission d'un nouvel événement<ref>En fait, on devrait plutôt appeler cela un message (qui est lui-même la notification d'un événement).
Lorsque cette méthode est invoquée, Python envoie au système d'exploitation exactement le même message-événement que celui qui se produirait si l'utilisateur enfonçait simultanément les touches <Ctrl>, <Maj> et <Z> de son clavier.
Ligne 686 :
Nous attirons votre attention sur la technique mise en œuvre pour provoquer un rafraîchissement de l'affichage dans le canevas par l'intermédiaire d'un événement, 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 »
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>.
Ligne 692 :
Lorsque nous avons construit la classe de ''widgets'' <code>ChoixVibra()</code>, 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 <code>montreCourbes()</code> 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.
<source lang=python line>
</
=== Commentaires ===
Ligne 791 :
La classe « Visage » servira à définir des objets graphiques censés représenter des visages humains simplifiés. Ces visages seront constitués d'un cercle principal dans lequel trois ovales plus petits représenteront deux yeux et une bouche (ouverte). Une méthode "fermer" permettra de remplacer l'ovale de la bouche par une ligne horizontale. Une méthode « ouvrir » permettra de restituer la bouche de forme ovale.
Les deux boutons définis dans la classe « Application » serviront respectivement à fermer et à ouvrir la bouche de l'objet « Visage » installé dans le canevas.</li>
<li>''Exercice de synthèse : élaboration d'un dictionnaire de couleurs.''
Ligne 826 ⟶ 825 :
Commencez par analyser ce script, et ajoutez-y des commentaires, en particulier aux lignes marquées : #*** , afin de montrer que vous comprenez ce que doit faire le programme à ces emplacements :
<source lang=python>
from Tkinter import *
Ligne 885 ⟶ 884 :
Projet(500, 300).mainloop()
</
Modifiez ensuite ce script, afin qu'il corresponde au cahier des charges suivant :
Ligne 910 ⟶ 909 :
<li>
[[Image:Apprendre à programmer avec Python 77.png|center|500px|capture d'écran de l'application]]
<source lang=python>
# Dictionnaire de couleurs
from Tkinter import *
Ligne 1 005 ⟶ 1 004 :
if __name__ == '__main__':
Application().mainloop()
</
</li>
<li>
(variante 3) :
<source lang=python>
from Tkinter import *
from random import randrange
Ligne 1 096 ⟶ 1 095 :
Projet(600, 600).mainloop()
</
</li>
</ol>
Ligne 1 104 ⟶ 1 103 :
{{références}}
<noinclude>[[Catégorie:Interface graphique]]</noinclude>
|