Activité 9 : AUTRES MINIS PROJETS AVEC LA FENETRE
Transcription
Activité 9 : AUTRES MINIS PROJETS AVEC LA FENETRE
Activité 9 : AUTRES MINIS PROJETS AVEC LA FENETRE GRAPHIQUE tkinther Classe de Terminale S - Spécialité ISN Après avoir travaillé sur les fenêtres graphiques voici la proposition de deux mini-projets. 1 - Réalisation d’une fenêtre intitulée « Bataille de boules de neige ! » Rappels : Le widget Canvas Le module tkinter dispose d’un widget nommé Canvas destiné à dessiner la fenêtre. Si on veut créer un canvas nommé canv, l’appel se fait comme pour tous les widgets de la manière suivante : canv=Canvas(emplacement, options) où emplacement est le nom de la fenêtre sur laquelle il est déposé et options indique les différentes propriétés du Canvas comme Options Effet bg Couleur du fond du Canvas Hauteur et largeur du Canvas (en pixels) height - width Dessiner sur le Canvas Sur un Canvas ici noté C, on peut dessiner différents types d’objets que l’on appelle item. Une ligne : ligne = C.create_line(x1,y1,x2,x2,options) dessine un segment reliant le point de coordonnées (x1,y1)en haut à gauche inclus et point (x2,y2) en bas à droite. Options Effet width Epaisseur de la ligne en pixels fill Couleur de la ligne Un rectangle : rect = C.create_rectangle(x1,y1,x2,x2,options) dessine un rectangle dont deux sommets opposés ont pour coordonnées (x1,y1)en haut à gauche et point (x2,y2) en bas à droite. Options Effet width Epaisseur du trait en pixels fill Couleur à l’intérieur du rectangle outline Couleur du trait Une ellipse ou une cercle rectangle : el = C.create_oval (x1,y1,x2,x2,options) dessine une ellipse dans un rectangle imaginaire dont deux sommets opposés ont pour coordonnées (x1,y1)en haut à gauche et point (x2,y2) en bas à droite. Options Effet width Epaisseur du trait en pixels fill Couleur à l’intérieur du rectangle outline Couleur du trait Un texte dans un Canvas : txt = C.create_text (x,y,options) affiche un texte aux coordonnées (x,y). Options anchor fill font text Effet Précise la position d’attache du texte par rapport au point de coordonnées (x,y). par défaut, le texte est centré autour du point indiqué (’center’). Il peut prendre les valeurs ‘n’, ‘ne’, ‘e’, ‘se’, ‘s’, ‘sw, ‘w’, ‘nw’, ou ‘center’ (par défaut). Couleur du texte Police de caractère utilisée (comme pour le widget Label) Une chaîne de caractère contenant le texte à afficher Exemples : Fond = Canvas(fenetre,width=800, height=40, bg=’black’) Fond.create_line(200, 300, fil=’green’) Fond.create_oval(20,20, 40,40, fill=’blue’) 2 - Placer des images. Il existe différents formats d’images. Le module tkinter travaille avec les images GIF (non animées). Ce sont des images en 256 couleurs possédant éventuellement une couleur de transparence. Pour placer une image, cela se passe en deux temps : a) On charge l’image dans une variable globale (ici fichierimg) à l’aide de la commande : fichierimg = PhotoImage(file=’image.gif’) (si le fichier se nomme ‘image.gif’ qui doit être placé dans le répertoire des scripts) b) On place l’image au point de coordonnées x,y sur le Canvas C avec la méthode : img = C.create_image(x,y,options) Le paramètre options permet de renseigner les propriétés. Par exemple : Options Effet _____________________________________________________________________________________________________________________ Année scolaire 2014-2015 – Lycée « Cordeliers-Victoire » DINAN – Enseignement de Spécialité ISN – Mardi 6 Janvier - © Doc. A. ROBERT 1 anchor image Comme pour l’objet text, indique la position du point de références (x,y) par rapport au reste de l’image. Il peut prendre les valeurs ‘n’, ‘ne’, ‘e’, ‘se’, ‘s’, ‘sw, ‘w’, ‘nw’, ou ‘center’ (par défaut). Indique l’image à afficher (fichierimg dans l’exemple ci-dessus) Travail : ajouter un père Noël sur le programme de bataille de boules de neige. L’image sera déposée sur « Agora » à télécharger Des exemples de résultats. Quelques indications plus précises sur la « bataille de boules de neige » L’idée finale est de commander la chute de la neige, de bloquer la chute de neige à l’aide d’un bouton et de faire glisser le père Noël au milieu de la neige. 1 – Il faut d’abord créer la fenêtre. Elle a pour dimension 800×400. On peut lui donner un titre « Bataille de boules de neige ». Quelques méthodes : Méthode Effet Fen.geometry (« 500×150 ») Redimensionne la fenêtre Fen en 500 pixels de large et 150 pixels de haut. Fen.title(T) Affiche le titre T dans la fenêtre. Fen.winfo.width() Renvoie la largeur (interne) de la fenêtre Fen. Fen.winfo.height Renvoie la hauteur (interne) de la fenêtre Fen. Fen.resizable(width=False) Empêche le redimensionnement (respectivement en largeur et en hauteur) de la Fen.resizable(height=False) fenêtre Fen. On peut placer les deux arguments dans les parenthèses en les séparant par une virgule pour n’utiliser qu’une seule ligne. Fen.place(x,y) Place l’objet créé aux coordonnées souhaitées. La fenêtre se présente sous la forme d’un fond « gris » dessiné dans un canevas. Fond=Canvas(fenetre,width=800,height=400,bg="grey") _____________________________________________________________________________________________________________________ Année scolaire 2014-2015 – Lycée « Cordeliers-Victoire » DINAN – Enseignement de Spécialité ISN – Mardi 6 Janvier - © Doc. A. ROBERT 2 Fond.place(x=0,y=0) On pourrait utiliser, pour placer le Canvas, la méthode grid(). Fond.grid(options) Les principales options (toutes facultatives) sont les suivantes : Options Effet row=… Indique respectivement le numéro de ligne et de colonne (la numérotation column=… commence à 0) rowspan=… Indique respectivement le nombre de lignes et de colonnes qu’occupe un widget columnspan=… (1 par défaut) padx=… Indique respectivement les distances minimales horizontale et verticales entre le pady=… widget et les bords de la grille (permet d’aérer la fenêtre). sticky=… Indique quel côté du widget est collé à la grille (centré par défaut). Les valeurs possible sont : ‘n’, ‘ne’, ‘e’, ‘se’, ‘s’, ‘sw, ‘w’, ‘nw’, ou ‘center’ (par défaut). Ce sont les points cardinaux. Fen.resizable(width=False) Empêche le redimensionnement (respectivement en largeur et en hauteur) de la Fen.resizable(height=False) fenêtre Fen. On peut placer les deux arguments dans les parenthèses en les séparant par une virgule pour n’utiliser qu’une seule ligne. Fen.place(x,y) Place l’objet créé aux coordonnées souhaitées. Attention, dans un programme, on fait le choix d’utiliser la méthode grid ou place, mais on ne mélange pas les deux méthodes. La méthode place a un inconvénient car parfois, les bordures de la fenêtre ou l’épaisseur des butons ne sont pas identiques d’un ordinateur à l’autre ou d’une version d’un système d’exploitation à une autre. 2 – Créer le rideau constitué de 10 lignes vertes d’inclinaison croissantes. Chaque ligne converge vers le milieu de la partie supérieure de la fenêtre, mais sans se rejoindre. (Les extrémités des lignes sont séparées de 5 pixels). Les lignes de gauche partent de x=0, mais leur départ à gauche est décalé de 10 pixels. Les lignes de droite partent de x=400, mais leur arrivée à droite est décalé de 10 pixels. Une boucle for est nécessaire (ou while). 3 – Créer la neige qui tombe. Il faut créer 200 boules, donc des cercles de dimension aléatoire et de fond blanc. 4 – Créer un texte sur le fond de l’image. (ce n’est pas obligatoire). Voir la méthode plus haut. Utiliser la police « Arial), taille 30 et de couleur jaune. 5 – Placer un père Noël, fixe d’abord. Utiliser la méthode create_image vue plus haut. Les objets images se superposent dans l’ordre dans lequel ils sont créés, c’est-à-dire que si l’on crée d’abord un personnage, puis le fond, on ne verra pas l’image puisqu’elle sera derrière le décor. En cours de programme, on peut modifier l’ordre grâce à deux méthodes : Méthode Effet Fen.tag.raise(obj) Place l’objet obj en premier plan du Canvas Fen Fen.tag.lower(obj) Place l’objet obj en arrière plan du Canvas Fen 6 – Faire glisser le père Noël à l’aide d’un bouton « Déplacement du père Noël ». Il faut créer une fonction par exemple glisse() pour déplacer le père Noël. Par exemple : def glisse() : Fond.coords(P,x,250) déplace l’image P, de x pixels, à l’ordonnée 250 (ici le for x in range(1200) : milieu de la fenêtre horizontalement). Fond.update() utilise la fonction update() qui permet de forcer la mise à jour Fond.coords(P,x,250) du Canvas. Sinon on ne voit que la première position (ici rien) et la dernière (ici Fond.update() rien non plus) Il faut créer le bouton à actionner. Le placer dans le coin gauche de la fenêtre. 7 – On peut actionner la chute de neige avec un bouton. Il faut créer la fonction chute() et créer un bouton « Faire tomber la neige ». 8 – On peut créer un bouton « QUITTER » Créer le bouton en bas de la fenêtre et au milieu. 9 – DEFI. Modifier l’ensemble du code avec le lancement de la chute de neige qui tombe réellement avec le bouton de commande « Faire tomber la neige ». _____________________________________________________________________________________________________________________ Année scolaire 2014-2015 – Lycée « Cordeliers-Victoire » DINAN – Enseignement de Spécialité ISN – Mardi 6 Janvier - © Doc. A. ROBERT 3 On pourra créer un bouton « Arrêter la neige » à placer au milieu du bord supérieur de la fenêtre. On pourra s’inspirer du code suivant : Voici un dernier exemple d'animation, qui fonctionne cette fois de manière autonome dès qu'on l'a mise en marche. from tkinter import * # définition des gestionnaires d'événements : def move(): "déplacement de la balle" global x1, y1, dx, dy, flag x1, y1 = x1 +dx, y1 + dy if x1 >210: x1, dx, dy = 210, 0, 15 if y1 >210: y1, dx, dy = 210, -15, 0 if x1 <10: x1, dx, dy = 10, 0, -15 if y1 <10: y1, dx, dy = 10, 15, 0 can1.coords(oval1,x1,y1,x1+30,y1+30) if flag >0: fen1.after(50,move) # => boucler après 50 millisecondes def stop_it(): "arret de l'animation" global flag flag =0 def start_it(): "démarrage de l'animation" global flag if flag ==0: # pour ne lancer qu'une seule boucle flag =1 move() #========== Programme principal ============= # les variables suivantes seront utilisées de manière globale : x1, y1 = 10, 10 # coordonnées initiales dx, dy = 15, 0 # 'pas' du déplacement flag =0 # commutateur # Création du widget principal ("parent") : fen1 = Tk() fen1.title("Exercice d'animation avec Tkinter") # création des widgets "enfants" : can1 = Canvas(fen1,bg='dark grey',height=250, width=250) can1.pack(side=LEFT, padx =5, pady =5) oval1 = can1.create_oval(x1, y1, x1+30, y1+30, width=2, fill='red') bou1 = Button(fen1,text='Quitter', width =8, command=fen1.quit) bou1.pack(side=BOTTOM) bou2 = Button(fen1, text='Démarrer', width =8, command=start_it) bou2.pack() bou3 = Button(fen1, text='Arrêter', width =8, command=stop_it) bou3.pack() # démarrage du réceptionnaire d'évènements (boucle principale) : fen1.mainloop() Dans ce script on définit la fonction move() . On notera l'utilisation de la méthode after(). Cette méthode peut s'appliquer à un widget quelconque. Elle déclenche l'appel d'une fonction après qu'un certain laps de temps se soit écoulé. Ainsi par exemple, window.after(200,qqc) déclenche pour le widget window un appel de la fonction qqc() après une pause de 200 millisecondes. Dans notre script, la fonction qui est appelée par la méthode after() est la fonction move() elle-même. Nous utilisons donc ici une technique de programmation très puissante, que l'on appelle récursivité. Pour faire simple, la récursivité est ce qui se passe lorsqu'une fonction s'appelle elle-même. On obtient bien évidemment ainsi un bouclage, qui peut se perpétuer indéfiniment si l'on ne prévoit pas aussi un moyen pour l'interrompre. Voyons comment cela fonctionne dans l’exemple : _____________________________________________________________________________________________________________________ Année scolaire 2014-2015 – Lycée « Cordeliers-Victoire » DINAN – Enseignement de Spécialité ISN – Mardi 6 Janvier - © Doc. A. ROBERT 4 La fonction move() est invoquée une première fois lorsque l'on clique sur le bouton « Démarrer ». Elle effectue son travail (c'està-dire positionner la balle), puis elle s'invoque elle-même après une petite pause. Elle repart donc pour un second tour, puis s'invoque elle-même à nouveau, et ainsi de suite indéfiniment... C'est ce qui se passe si on ne prend pas la précaution de placer quelque part dans la boucle une instruction de sortie. Il s'agit d'un simple test conditionnel : à chaque itération de la boucle, on examine le contenu de la variable flag à l'aide d'une instruction if. Si le contenu de la variable flag est zéro, alors le bouclage ne s'effectue plus et l'animation s'arrête. flag étant une variable globale. On peut changer sa valeur à l'aide d'autres fonctions, celles associées aux boutons « Démarrer » et « Arrêter ». On obtient ainsi un mécanisme simple pour lancer ou arrêter notre animation : Un premier clic sur le bouton « Démarrer » assigne une valeur non-nulle à la variable flag, puis provoque immédiatement un premier appel de la fonction move(). Celle-ci s'exécute et continue ensuite à s'appeler elle-même toutes les 50 millisecondes, tant que flag ne revient pas à zéro. Si l'on continue à cliquer sur le bouton « Démarrer », la fonction move() ne peut plus être appelée tant que la valeur de flag vaut 1. On évite ainsi le démarrage de plusieurs boucles concurrentes. Le bouton « Arrêter » remet flag à zéro, et la boucle s'interrompt. _________________________________________________________________________________________________________ Améliorer les programmes. Cette définition des boutons avec la méthode de mise en place de widgets est un peu plus simple et parfois un peu plus lisible. Button(fen1,text='Quitter',command=fen1.destroy).pack(side=BOTTOM) Button(fen1,text='Gauche',command=depl_gauche).pack() Button(fen1,text='Droite',command=depl_droite).pack() Button(fen1,text='Haut',command=depl_haut).pack() Button(fen1,text='Bas',command=depl_bas).pack() L’avantage est de faire l’économie de la variable intermédiaire bou1 (par exemple). Nous avons utilisé cette variable pour bien dégager les étapes successives de la démarche, mais elle n’est pas toujours indispensable. Le simple fait d’invoquer la classe Button (ici), provoque l’instanciation d’un objet de cette classe, même si on ne mémorise pas la référence de cet objet dans une variable. Tkinter la conserve de toute façon dans sa représentation interne de la fenêtre. En procédant ainsi, la référence est perdue pour le reste du script, mais elle peut tout de même être transmise à une méthode de mise en page telle que pack() (ici) au moment de l’instanciation, en une seul instruction composée. Créer une nouvelle variable pour n’y faire référence qu’une seule fois (et directement après sa création) n’est pas une pratique recommandable puisqu’elle consiste à réserver inutilement un certain espace mémoire. _________________________________________________________________________________________________________ _____________________________________________________________________________________________________________________ Année scolaire 2014-2015 – Lycée « Cordeliers-Victoire » DINAN – Enseignement de Spécialité ISN – Mardi 6 Janvier - © Doc. A. ROBERT 5