ISN - INTERFACE GRAPHIQUE- 12 janvier 2014 TS2
A : le module Tortue
Python possède de nombreuses bibliothèques regroupant des catégories de fonctions. Elles sont appelées des modules, au même titre que les fichiers ".py" que vous créez et qui deviennent vos propres modules.
Dans EduPython, si vous souhaitez réaliser une nouvelle figure à l’aide de la tortue, cliquer sur le bouton Nouveau Fichier... et choisissez le mode Tortue. Un nouveau programme comportant déjà quelques lignes de code est généré :
# Créé par ... , le ... avec EduPython from lycee import *
import turtle as tortue ... .
tortue . mainloop()
Pour utiliser le module "Tortue", écrivez au début de votre programme : from tortue import * (sans oublier "*")
Cette tortue est une interface graphique dans laquelle vous avez un traceur que l'on va apprendre à commander.
Une documentation très complète est disponible sur : docs.python.org
Au départ la tortue (le traceur) est au centre de l'écran (de coordonnées (0,0)) et orienté vers l'est.
Les déplacements :
fd(dist) : fait avancer la tortue de dist
bk(dist) : la même chose en reculant
left(angle) : change la direction du mouvement en la faisant tourner de angle vers la gauche(en degrés par défaut)
right(angle) : de même vers la droite
goto(x,y) : déplace la tortue au point de coordonnées (x,y)
circle(r, angle) : trace un cercle de rayon r.
Le tracé du cercle commence à l'endroit où est la tortue, puis tourne vers la gauche. Si aucun angle n'est précisé, trace le cercle un entier, sinon un arc de cercle.
undo() : annule la dernière action (peut être répété).
reset() : remet la tortue à l'origine et efface le tracé
home() : remet la tortue à l'origine mais sans effacer le tracé
dot(r,"couleur") : trace un point de rayon r et de la couleur choisie (ex : "red", "blue" etc...) Propriétés du traceur
On peut évidemment changer les paramètres du traceur :
pu() (ou penup()) : lève le "stylo" , la tortue se déplace, mais sans tracé
pd() (ou pendown()) : redescend le "stylo"
pensize(nb) : fixe la largeur du "stylo" à nb
color("coul") : fixe la couleur du stylo ("red", "blue" etc..)
speed(n) : règle la vitesse. Si n = 0, le tracé est quasi instantané, si n = 10, il est rapide, si n = 1 il est très lent
La fenêtre
Les propriétés de la fenêtre peuvent également être modifiées :
setup(largeur,hauteur) : règle la largeur et la hauteur (en pixels) de la fenêtre
bgcolor("coul") : fixe la couleur de l'arrière-plan
bye() : permet de fermer la fenêtre
S'il n'y a aucune boucle dans votre programme, aucune pause, vous n'aurez guère le temps de voir votre tracé
mainloop() : permet d'entrer dans une boucle d'attente
ceci vous donne le temps de voir votre tracé, la fenêtre se ferme en cliquant sur la croix
exitonclick() : permet de fermer la fenêtre avec un clic
clear() : efface la fenêtre, sans bouger la tortue I) Avancer, reculer, tourner
tortue.forward(n) et tortue.back(n)
Fait respectivement avancer ou reculer la tortue dans la direction où elle regarde de n pas (n pouvant être entier ou non)
tortue.left(a) et tortue.right(a)
Fait respectivement tourner la tortue vers la gauche ou la droite de a degrés. (Aucun tracé n’est effectué, juste une rotation de la tête)
Code: Une maison.
from lycee import * tortue . forward(100) tortue . right (90) tortue . forward(100) tortue . right (90) tortue . forward(100) tortue . right (90) tortue . forward(100) tortue . right (30) tortue . forward(100) tortue . right ( 120) tortue . forward(100) tortue . mainloop()
Code: Une église.
from lycee import *
import turtle as tortue tortue . left(90) tortue . forward(100)
B = acos(40 / 100) tortue . right (90 - B)
tortue . forward(100) C = 180 - 2 * B tortue . right ( 180 - C)
tortue . forward(100) tortue . right (90 - B) tortue . forward(20) tortue . left(90) tortue . forward(100) tortue . right (50) FG = 20 / cos(40) tortue . forward(FG) tortue . right (40)
HG=80 - sqrt(FG * FG - 20 * 20) tortue . forward(HG)
tortue . right (90) tortue . forward(200) tortue . mainloop()
Code: Tracer un polygone régulier à n côtés.
from lycee import * import turtle as tortue
n = demande(" Nombre de côtés (au moins 3)")
for i in range(n):
tortue . forward(50) tortue . left( 360/n) tortue . mainloop()
II) Tracer des cercles
tortue.circle(rayon) ou tortue.circle(rayon,angle)
– Si rayon>0 : Trace un cercle de rayon rayon à partir de la position de la tortue et en tournant dans le sens trigonométrique.
– Si rayon < 0 : Trace un cercle de rayon |rayon| dans le sens anti-horaire.
– Si angle est précisé, trace un arc de cercle de rayon |rayon| avec une ouverture de angle (en degré). Si angle n’est pas précisé, le cercle est tracé dans son intégralité.
La spirale est obtenue en traçant bout à bout des quarts de cercle de centres successifs A, B, C et D.
Code: Tracer une spirale.
from lycee import * import turtle as tortue n = 10
for i in range(n):
tortue . circle (5*i,90) tortue . mainloop()
Remarque:
Attention, on ne connaît a priori pas le centre de ce cercle... c’est d’ailleurs ce qui peut faire l’intérêt de l’algorithme !
On veut tracer l’œuf de Pâques ci-contre.
Données : OA = OB = OC = r, C1 est un demi-cercle de diamètre [AB], C2 est un arc de cercle de centre A et passant par B et E, C3 est un arc de cercle de centre C et passant par E et D, enfin C4 est un arc de cercle de centre B et passant par D et A.
Code: Tracer un œuf de Pâques.
from lycee import * import turtle as tortue r = 100
tortue . right (90) tortue . circle (r, 180) tortue . circle (2 * r, 45)
tortue . circle (r * (2 - sqrt(2)), 90) tortue . circle (2 * r, 45)
tortue . mainloop()
Code: Le yin et le yang from lycee import *
import turtle as tortue r = 100
tortue .up () tortue . forward(r) tortue . down ()
Code: Le yin et le yang.
from lycee import * import turtle as tortue r = 100
tortue .up () tortue . forward(r) tortue . down () tortue . left(90)
tortue . circle (2 * r) tortue . circle (r, 180) tortue . circle (-r, 180) tortue . hideturtle() tortue . mainloop()
tortue . left(90)
tortue . circle (2 * r) tortue . circle (r, 180) tortue . circle (-r, 180) tortue . hideturtle() tortue . mainloop()
Code: Un soleil avec 120 rayons.
from lycee import * import turtle as tortue i = 0
while i < 120:
tortue . right(90) tortue . forward(100) tortue . right( 180) tortue . forward(100) tortue . right(90) tortue . circle (50 , 3) i = i + 1
tortue . mainloop()
III) La tortue : Afficher, Cacher, Vitesse tortue.showturtle() tortue.hideturtle()
A pour effet de respectivement cacher ou montrer la tortue à l’écran. Pour des questions d’esthétisme, on peut par exemple vouloir cacher la tortue en fin de tracé.
tortue.speed(v)
Permet de régler la vitesse de la tortue. v est un nombre entier entre 1 et 10, 1 étant la vitesse la plus lente et 10 la plus rapide.
IV) Le crayon : lever, baisser, taille, couleur
On peut pour certains dessins avoir besoin de déplacer la tortue sans laisser de trace.
tortue.up() tortue.down()
A pour effet de respectivement lever et baisser le crayon
tortue.pencolor(texte) ou tortue.pencolor(rouge,vert,bleu) Définit la couleur du crayon.
– On peut entrer un texte entre guillemets parmi (entre autres) : ’aqua’, ’beige’, ’black’, ’blue’,
’brown’,
’chocolate’, ’fuchsia’, ’gold’, ’gray’, ’green’, ’indigo’, ’khaki’, ’maroon’, ’orange’, ’red’, ’white’, ...
– On peut aussi définir sa propre couleur en paramétrant les composantes rouge, vert et bleu de la couleur (chaque composante étant un nombre entre 0 et 1).
Code: Le drapeau européen.
from lycee import * import turtle as tortue tortue . pensize(2)
tortue . pencolor(0.9 , 0.9, 0.2) tortue . bgcolor( 'blue ')
for etoile in range (12 ):
tortue . down ()
for branche in range (5):
tortue . forward(30) tortue . left(144) tortue .up()
tortue . forward(50) tortue . left(30) tortue . mainloop()
V) L’écran : effacer, colorer le fond, afficher un texte tortue.reset()
Efface l’écran et repositionne la tortue dans sa position initiale tortue.clear()
Efface l’écran mais la position du crayon reste inchangée tortue.write(texte)
Affiche le texte texte à l’emplacement de la tortue. Celle-ci ne se déplace pas lors de l’affichage.
De nombreuses autres fonctionnalités sont disponibles sur le site officiel : http ://docs.python.org/3.2/library/turtle.html
Un exemple simple : from turtle import*
colormode(255) #pour utiliser les couleurs en mode RGB (sinon colormode(1)) pu() #on deplace le point de départ pour centrer la figure (stylo levé) bk(100) #on recule de 100
pd( )#on descend le stylo for i in range(1,7):
color((155,255-30*i,200))#pour changer de couleur quand i change fd(10*i)
left(90) fd(10*i) left(90) fd(10*i) left(90) fd(10*i) left(90) pu() fd(10*i) pd() pu() fd(40)
pd() #à ce stade le traceur est orienté vers l'est left(90) #on veut que le cercle se trace vers le haut circle(150)
mainloop()
TP: réaliser un jeu de pendu
Réaliser à l'aide de la tortue un dessin de gibet avec son pendu.
Ecrire "mainloop()" à la fin de votre programme pour pouvoir facilement fermer la fenêtre graphique
B
:C'est une bibliothèque d'objets graphiques (widgets), organisés en classes. En voici quelque exemples : fenêtre (classe Tk), bouton à cliquer (classe Button), case à cocher (classe Checkbutton), étiquette (classe Label), zone de saisie (classe Entry), menu (classe Menu), zone graphique (classe Canvas), etc…
On crée un objet en précisant ses paramètres (ou options) dans le nom de sa classe, séparés par des virgules.
On peut ensuite le modifier en appliquant des «méthodes».( un peu comme une fonction) A. Présentations
1. Taper le script suivant et l’exécuter.
from tkinter import * fen = Tk() L = Label(fen, text='Bonjour tout le monde', fg='blue') L.pack()
E = Entry(fen, bg='grey') E.pack()
B = Button(fen, text='Quitter', command = fen.destroy) B.pack()
fen.mainloop()
# importe la bibliothèque
# crée une fenêtre fen
# crée une étiquette L
# Méthode pack : affiche et positionne l'étiquette L
# crée une zone de saisie E
# Méthode : affiche/positionne la zone de saisie E
# crée un bouton B
# Méthode: affiche/positionne le bouton B
# Méthode mainloop : affiche la fenêtre et attend les événements
Voici ce que cela donne :
Modifier certains paramètres pour observer les différences.
On découvre ici quatre classes d'objets : Tk(), Button(), Label() et Entry() à partir desquelles sont définis les objets ( widgets) fen, B, L et E
- on a utilisé quatre paramètres : text= , fg= , bg= ,command=
- et on a appliqué trois méthodes ( avec un point) : … .pack(), ... .mainloop(), … .destroy() Le module tkinter ("Tool kit interface") de Python permet de créer une interface graphique (En anglais GUI : graphical user interface)
2. En observant le programme précédent et les indications suivantes, faites afficher la fenêtre ci-contre.
Elle doit se fermer si on clique sur un des boutons.
fen.title( 'titre' ) Affiche titre de la fenêtre
fen.geometry( '500x150' )
Dimensionne la fenêtre en 500 pixels de large par 150 de haut
B : Action
Il est fondamental d'avoir un peu d'interactivité. Pour cela le widget Button à un paramètre dédié.
command= fonc Relie un clic sur le bouton à une fonction (sans parenthèse) ou une méthode
Notez que ce paramètre ''command'' était utilisé avec la méthode ''destroy'' dans le programme précédent.
1. Cet exemple illustre son utilisation avec une fonction.
#### La fonction précède le programme #####
def change() : if B.cget('text')=='JOUR':
B.config(text='NUIT')
else :
B.config(text='JOUR')
#### Corps du programme #####
from tkinter import * fen=Tk() fen.title('Bonjour')
B=Button(fen,text="JOUR",width=30,command=change) B.pack()
fen.mainloop()
2. L'adapter en un programme qui affiche la fenêtre de gauche, et la fenêtre de droite en cas de clic sur le bouton.
Faisons un petit point sur les instructions observées.
Widgets / objets
fen = Tk() Défini une fenêtre fen
B = Button ( fen,... ) Défini un bouton dans la fenêtre fen, selon certains paramètres L = Label( fen, text ='x' , .. ) Défini un texte x dans la fenêtre fen
E = Entry(fen,..) Défini une zone de saisie, où l'on peut taper un texte Paramètres
fg=' ' , bg=' ' Couleur du texte, de l'arrière plan
height=' ' , width=' ' Hauteur, et la largeur. Pas d'effet sur la police font= '' '' Police utilisée et mise en forme. Ex : ''arial 15 bold '' text=' ' Texte à afficher. Pour Button et Label seuls.
command= fonc Relie un clic à une fonction ( sans parenthèse) à exécuter. Button seul.
Méthodes
w.cget( ''…'' ) Renvoie la valeur du paramètre indiqué entre '' .. '' ,de l'objet w w.config(..,.., ) Modifie un ou des paramètres ( texte, couleur, position, …..) de w w.pack() Affiche et positionne l'objet w en fonction de ceux déjà présents
w.destroy() Efface l'objet w
C. Dialogue
Le widget Entry et la méthode dédiée get() ont pour fonction de récupérer des données saisie à l'écran.
Le contenu tapé est une chaîne de caractères, on procède alors si nécessaire à un trans typage.
NB : La méthode cget() vue précédemment pour les autres widgets est différente : il fallait préciser l'option.
Exemple : ce programme demande à l'utilisateur son année de naissance puis affiche son âge (en 2014) def reponse():
age=2014-int(entre_annee.get())
texte="Bonjour . \n 2014 est l'année de tes "+str(age)+" ans"
bouton.config(text=texte)
# Corps du programme , interface from tkinter import *
fen=Tk()
fen.title("SALUT")
titre_annee=Label(fen,text="En quelle année es tu né? ",font="arial ") titre_annee.pack()
entre_annee=Entry(fen, width=6,font="arial ")
entre_annee.pack()
bouton=Button(fen,text="Envoi",bg='grey',fg='white',command=reponse) bouton.pack()
fen.mainloop()
# Fonction qui affiche l'âge
# Saisie et calcul l'âge, converti en 'entier'
# texte réponse. Converti l'âge en 'chaîne'
# Affiche la réponse sur le 'bouton'
# Label : question posée
# Entry : zone de saisie
# Button : au clic, appelle la fonction reponse
Modifier ce programme pour qu'il demande le nom de l'utilisateur, puis donne la réponse dans un widget en dessous du bouton Envoi. Optimiser l'affichage (police, taille widgets) pour obtenir un résultat comme ce qui suit.
Pour info : on peut aussi écrire dans un Entry avec les méthodes … .insert() et ... .delete() E.insert( i , text )
E.insert( INSERT , text ) E.insert( END , text )
Insert dans E le texte text : à la position i
ou à la place du curseur ou à la fin du contenu existant E.delete( i )
E.delete( a, b ) E.delete( 0,END )
Efface le caractère à la position i ;
ou les caractères entre les positions a et b ; ou tout le champ de texte
D . Mise en page
La méthode pack() utilisée jusque là pour afficher les widgets est pratique pour des programmes simples.
On lui préférera la méthode grid() pour un projet plus complet. Celle-ci place les widgets sur une grille organisée en rangées et colonnes ( comme en HTML). En voici quelques paramètres.
row= numéro de la ligne ( rangée) du widget. Début à 0.
column= numéro de la colonne du widget.
rowspan= nombre de ligne qu'occupe le widget. 1 par défaut columnspan= nombre de colonnes qu'occupe le widget. 1 par défaut padx= largeur de marge verticale entre la grille et le widget pady= largeur de marge horizontale entre la grille et le widget
sticky= Coin ou côté du widget collé à la grille ('n','s','e','w','ne','nw','se','sw'). Centré par défaut Ainsi E.grid(row=0,column=0,padx=10) place le widget E en haut à gauche, avec une marge verticale de10
Modifier le programme précédent, en remplaçant les méthodes pack, pour arriver à l'apparence suivante.
E. Interface pour le juste prix
L'ordinateur doit proposer de faire deviner un nombre entre 30€ et 100€ choisi au hasard.
Il doit afficher « Vous avez gagné en .. coups » à la fin ( Pas de limites de coups.)
Conseil : une version du programme «juste prix» est rappelé page suivante, avec des indications de départ.
- Vous devez créer une interface inspirée du « D » précédent.
- Votre programme aura une fonction jouer() devant gérer les réponses du joueur et le décompte des essais.
# Programme juste prix (interface à ajouter)
##### Fonction à compléter ( tests , affichage) ########
def jouer():
''' Demande un prix, le teste, puis affiche la réponse ''' global prix, coup, proposition
################### Corps du programme ######################
from random import*
prix = randint(30,100) proposition = 0 coup = 1 fin=False
## instrumentation pour debuguer : à activer ou pas selon besoin print('chut, la réponse est :', prix)
## Cœur du programme, à intégrer et adapter à la fonction jouer() en début de programme while(fin==False):
proposition=int(input('proposez un prix')) if proposition < prix :
print("C'est plus que "+ str(proposition)) elif proposition > prix :
print("C'est moins que "+ str(proposition)) else :
print("Vous avez gagné, \n en " +str(coup)+" coup(s)") fin=True
coup = coup +1
### Interface à créer :widgets fenêtre, Entry, Button , Label ###
from tkinter import * fen=Tk()
fen.title("LE JUSTE PRIX") fen.mainloop()
Éléments de réponses
Si vous êtes bloqués ou pour comparer A : Présentations
from tkinter import * fen = Tk()
fen.title('Ma première fenêtre') fen.geometry('300x100')
L = Label(fen, text='Ecrivez pour voir !', fg='orange') L.pack()
E = Entry(fen, fg='purple') E.pack()
B1 = Button(fen, text='Au revoir', command = fen.destroy,fg='red') B1.pack()
B2 = Button(fen, text='Et à bientôt', command = fen.destroy,fg='green') B2.pack()
fen.mainloop()
B : Action
from tkinter import * def boum():
L.config(text="BOUM", fg="red") B.config(text="J'avais prévenu !") fen=Tk()
fen.title("TEST") fen.geometry("200x50")
L=Label(fen,text="ATTENTION DANGER",fg="blue",bg="white") L.pack()
B=Button(fen,text=" Surtout n'appuyer sur le bouton!",command=boum) B.pack()
fen.mainloop()
## Fonction qui modifie le Label ##
## corps du programme ###
C : Dialogues
# Fonction qui salut et affiche l'âge def affiche():
age=2014-int(entre_annee.get()) ## récupération et conversion de l'année en entier nom=entre_nom.get() ## Récupération du nom
texte="Bonjour "+nom+". \n 2014 est l'année de tes "+str(age)+" ans" ## Réponse reponse.config(text=texte) ## Affichage de la réponse
# Corps du programme et interface from tkinter import *
fen=Tk()
fen.title("SALUT")
titre_nom=Label(fen,text="Quel est ton prénom ?",font="arial") titre_nom.pack()
entre_nom=Entry(fen,font="arial") entre_nom.pack()
titre_annee=Label(fen,text="En quelle année es-tu né? ",font="arial ") titre_annee.pack()
entre_annee=Entry(fen, width=9,font="arial ") entre_annee.pack()
bouton=Button(fen,text=" Envoi",width=8,font="arial",bg='grey',fg='white',command=affiche) bouton.pack()
reponse=Label(fen,text="Ma réponse",font="arial",bg='white',fg='grey') reponse.pack()
fen.mainloop() D : Mise en page
# Fonction qui salut et affiche l'âge def affiche():
age=2014-int(entre_annee.get()) ## récupération et conversion de l'année en entier nom=entre_nom.get() ## Récupération du nom
texte="Bonjour "+nom+". \n 2013 est l'année de tes "+str(age)+" ans" ## Réponse reponse.config(text=texte) ## Affichage de la réponse
# Corps du programme et interface from tkinter import *
fen=Tk()
fen.title("SALUT") fen.geometry("500x200")
titre_nom=Label(fen,text="Quel est ton prénom ?",font="arial") titre_nom.grid(row=0,column=0,sticky='w',padx=10,pady=10) entre_nom=Entry(fen,font="arial")
entre_nom.grid(row=0,column=1,sticky='w',padx=10,pady=10) titre_annee=Label(fen,text="En quelle année es tu né ? ",font="arial ") titre_annee.grid(row=1,column=0,sticky='w',padx=10,pady=10) entre_annee=Entry(fen, width=9,font="arial ")
entre_annee.grid(row=1,column=1,sticky='w',padx=10,pady=10)
bouton=Button(fen,text=" Envoi",width=8,font="arial",bg='grey',fg='white',command=affiche) bouton.grid(row=2,column=0,padx=10,pady=10)
reponse=Label(fen,text="Ma réponse",font="arial",bg='white',fg='grey',width='25', height='3') reponse.grid(row=2,column=1,sticky='w',padx=10,pady=10)
fen.mainloop()
TP2 : La gestion des images
Déplacer un objet dans une interface graphique
Les événements
Résultats des événements : exempleEvt.py L'affichage temporisé : compteRebours.py Diriger un objet : mouvementsBouton.py
Ressources
Partie tkInter des fiches hypertexte Tout tkInter, mais en anglais La page de Wikipédia
Exercice :
Créer l’interface ci-dessous, le fond est dans le fichier fond.gif (500*100), la fusée est dans le fichier fusee.gif (85*60).
Quand l’utilisateur appuie sur le bouton Start, la fusée parcourt horizontalement la largeur de la fenêtre puis apparaît à nouveau à gauche. Si l’utilisateur appuie sur stop, elle s’arrête.
Pour cet exemple, diriger l'objet à l'aide des touches fléchées du clavier.
Les fichiers nécessaires sont ici et là
Nous utiliserons les commandes :fond.coords(). after()fenetre.bi Un wiki sur ce thème, avec les principales commandes
Pour débuter
#Fusée
from tkinter import *
#Position initiale de la fusée x=20
y=20 a=0
#Fond et Canevas fenetre=Tk()
fenetre.geometry("600x100") #détermination de la taille de la fenêtre principale fenetre.title("Fusée") #titre de la fenêtre principale
fond=Canvas(fenetre, bg='white',width=500,height=100) #Canevas n°1 = fond fond.pack(side=LEFT)
zone_bouton=Canvas(fenetre, bg='red',width=100,height=100) zone_bouton.pack(side=RIGHT)
#L'image de fond
photo=PhotoImage(file="nuit.gif") # creation d'un objet de la classe PhotoImage img=fond.create_image(0,0,anchor=NW,image=photo)
#boutons et invitations
bouton1=Button(zone_bouton,bg="gainsboro",fg="black",text="Start",command=demarrage) bouton2=Button(zone_bouton,bg="gainsboro",fg="black",text="Stop",command=arret) bouton1.grid(column=1,row=1,columnspan=2)
bouton2.grid(column=1,row=3,columnspan=2)
#placer la fusée au démarrage
photo2=PhotoImage(file="fusee.gif") # creation d'un objet de la classe PhotoImage img2=fond.create_image(x,
Il n'y a plus qu'à faire bouger tout ça !