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