Vous pouvez me contacter via Facebook pour questions & suggestions :
Page Facebook relative à mon site
Python propose un module dénommé "turtle" (tortue en français) qui permet de dessiner des figures géométriques dans une fenêtre.
Ces dessins peuvent être sauvegardés sous forme d'images PNG.
Dans une deuxième partie de ce chapitre, je vous montre qu'il existe une autre solution : le module tkinter.
Vous pouvez aborder directement la deuxième partie : dessiner avec tkinter.
En effet le module turtle est surtout destiné à l'apprentissage de la programmation par des "kids".
C'est une alternative à langage Scratch.
Maintenant un survol de la première partie n'est pas inintéressant.
En le lisant vous pouvez redécouvrir certains notions de géométrie.
Ainsi, savez-vous dessiner une étoile à 5,7,9 branches ???
Turtle signifie en anglais "tortue".
C'est avec ce module que l'on peut réaliser dans Python de jolies figures géométriques.
Le principe est simple : on dessine en déplaçant un crayon (ou "turtle" ou tortue ou curseur).
Dans ce chapitre j'emploie le plus souvent le terme "curseur". Ce curseur a la forme d'une pointe de flèche.
Créez un nouveau dossier à la racine de C: et nommez le "python_dessins". Tous les scripts de ce chapitre seront stockés dans ce répertoire.
Turtle met en place un repère à deux dimensions dans la fenêtre de dessin. Attention ce repère est invisible.
Les axes X & Y (invisibles) et coupent hauteur et largeur de la fenêtre en leur milieu.
L'origine du repère est donc le centre de la fenêtre turtle.
La tortue est au départ situé au point(0,0) du repère et apparait sous forme d'une flèche orientée vers la droite. Ce qui signifie que tout déplacement avant du crayon se fera vers la droite.
>>>from turtle import * >>>pen() >>>speed(1) >>>forward(200) >>>left(90) >>>forward(100) >>>right(90) >>>forward(100) >>>left(90) >>>forward(100) >>>left(90) >>>forward(300) >>>
from turtle import * : importation de toutes les fonctions du module turtle.
pen() : une zone de dessin apparait avec la "tortue" au milieu sous forme d'une flèche, la fenêtre
graphique a pour titre : "Python turtle graphics".
speed(1) : réglage de la vitesse de déplacement de la tortue ; une fenêtre légendé "Python Turtle Graphic"
est alors affiché.
forward(200) : trait horizontal de 200 pixels
Left(90) : la tortue tourne à gauche de 90° ; flèche orientée désormais vers le haut
forward(100) : trait vertical de 100px
Un carré est un polygone régulier de 4 côtés égaux et 4 angles égaux (angles droits).
Pour sauvegarder notre travail nous passons en mode programme !
#nom programme : tortue_carre.py
#objet : dessiner un carre
from turtle import *
pen()
speed(1)
pencolor('red')
c =input('côté du carré ? : ')
c=eval(c)
#convertir en numérique la saisie
forward(c)
left(90)
forward(c)
left(90)
forward(c)
left(90)
forward(c)
exitonclick()
Par défaut la couleur du trait est noir. Ici je demande qu'il soit rouge avec la fonction pencolor().
Le côté du carré est saisi dans la variable c.
Rappel : toute saisie avec la fonction input() est de type string. Il faut donc convertir le contenu de c en
un numérique avec la fonction eval().
Ensuite vous avez 4 fois le même couple d'instructions : forward(c) et left(90)
Ne pas oubliez de terminer le programme avec l'instruction mainloop() / exitonclick() pour redonner la "main à l'utilisateur".
Différences : exitonclick() maintient la fenêtre ouverte jusqu'à un clic, tandis que mainloop() la garde ouverte indéfiniment jusqu'à sa fermeture manuelle.
On aurait pu écrire le code d'une façon beaucoup plus concise grâce à une boucle.
... for i in range(5) : #pour i allant de 0 à 5 exclu forward(c) left(90)
# nom programme : tortue_carre_bis.py
from turtle import *
pen()
pencolor('purple')
speed(5)
for i in range(50):
forward(20 + (i*10) )
left(90)
mainloop()
A chaque passage dans la boucle l'argument de la commande forward est plus grand de 10, donc on dessine un labyrinthe.
Je veux réaliser un programme très généraliste capable de produire n'importe quel polygone régulier : carré, pentagone, hexagone, octogone.
Dans tous les cas la somme des "virages à gauche" doit être égale à 360° afin que la tortue revienne à sa position de départ.
#nom prog. : tortue_polygone.py
#objet : dessiner un polygone régulier de n côtés (4 ou 5 ou 6 ou 8)
from turtle import *
pen()
n ="2"
while n not in "4568":
n = input ("nombre de côtés du polygone : 4/5/6/8: ")
while True:
cote = input("Entrez le côté du polygone régulier : ")
if cote.isdigit():
break
else:
print("Ce n'est pas un entier !")
# conversions
n =int(n) #conversion
cote= int(cote)
angle=360 / n
for i in range(n):
forward(cote)
left(angle)
exitonclick()
Notez les contrôles de saisie efficaces.
La fonction isdigit() s'applique à une chaine et retourne True si celle-ci ne contient que des chiffres.
Donc cette fonction est idéale pour vérifier si vous avez bien saisi un entier positif.
nombre de côtés du polygone : 4/5/6/8: 6 côtés nombre de côtés du polygone : 4/5/6/8: 6 Entrez le côté du polygone régulier : 150pixels Ce n'est pas un entier ! Entrez le côté du polygone régulier : 150
Malgré des erreurs de saisie, le script ne plante pas !
Ci-dessous une étoile à 7 branches.
Il faut tracer 7 segments.
Après avoir desssiné un segment il faut tourner à droite de 154° (180-(180/7)
De façon générale l'angle de virage après chaque segment est : 180-(180/N) (N le nombre de bras de l'étoile).
from turtle import *
pen()
setup(600,600)
speed(1)
pensize(2)
n ="10"
while n not in "579":
n = input ("nombre de branches de l'étoile 5 ou 7 ou 9: ")
# Paramètres de l'étoile
branches = int(n)
angle = 180 - (180 / branches) # angle de rotation entre deux traits
# Dessin
for i in range(branches):
forward(150) # longueur du segment (à ajuster)
right(angle)
hideturtle()
mainloop()
Ce script permet de dessiner une étoile à 5 ou 7 ou 9 bras.
Il faut utiliser la fonction cercle(rayon, [angle]).
Le seul argument obligatoire est le rayon.
# nom programme : tortue_cercles.py
import turtle as tu
tu.pen()
tu.pencolor('orange')
tu.speed("slow")
for i in range(20):
tu.circle(i +30)
tu.exitonclick()
En raison de la technique d'importation du module avec un alias, je dois préfixer les fonctions du module avec cet alias.
L'argument de la fonction speed() peut être un entier (entre 0 et 10) mais aussi une chaine : "fast", "normal", "slow", …
Remarque : les cercles sont dessinés dans le sens contraire des aiguilles d'une montre.
Je dessine des cercles donc la fonction circle() n'a qu'un argument : le rayon !
Dessiner 15 ronds de la gauche vers la droite.
# nom programme : tortue_cercles_bis.py
import turtle as tu
tu.pen()
tu.setup(500,500)
tu.pencolor('orange')
tu.pensize(5)
tu.speed(5)
tu.up()
tu.backward(250)
tu.down()
for i in range(15):
tu.circle(-30)
tu.forward(30)
tu.exitonclick()
Comment éviter le trait entre chaque cercle ?
Il suffit de lever le crayon pour ce trajet.
La fonction circle() accepte un deuxième paramètre : l'angle (par défaut 360°).
# tortue_arcs.py
# dessiner un bonhomme de neige
from turtle import *
pen()
setup(600,600)
speed('slow')
pensize(2)
penup()
goto(0,-200)
pendown()
circle(80, 180,)
circle(-50,180)
circle(-50,180)
circle(80,180)
mainloop()
Les méthodes up() & penup() sont équivalentes. Il en est de même pour pendown() & down().
Je dessine 4 arcs de cercle de rayon 180° mais notez que le rayon est tantôt positif et tantôt négatif.
Vous pouvez souhaitez que la forme dessinée soit remplie d'une certaine couleur.
Reprenons le programme "tortue_polygone.py" et améliorons le !
#nom prog. : tortue_polygone_plus.py
#objet : dessiner un polygone régulier de n côtés (4 ou 6 ou 8)
# polygone rempli de violet
setup(600,600)
speed('slow')
pencolor('purple')
pensize(5)
fillcolor('lime')
bgcolor('pink')
# conversions
n =int(n) #conversion
cote= int(cote)
angle=360 / n
begin_fill()
for i in range(n):
forward(cote)
left(angle)
end_fill()
exitonclick()
Le graphique obtenu après avoir saisi 5 et 100 :
# nom programme : tortue_infos py
from turtle import *
pen()
hideturtle()
for i in range(4): #boucle effectuée 4 fois (0 à 3)
print ("position tortue : ", position())
forward(200)
left(90)
# fin boucle
print("-----")
up()
home()
print ("position tortue : ", position())
mainloop()
La fonction position() retourne les coordonnées x et y de la tortue à un stade donné.
La fonction home() déplace le curseur à l'origine du repère (x = 0 ; y = 0).
La fonction hideturtle() masque le curseur
position tortue : (0.00,0.00) position tortue : (200.00,0.00) position tortue : (200.00,200.00) position tortue : (0.00,200.00) ----- position tortue : (0.00,0.00)
En parenthèse la valeur de l'abscisse puis celle de l'ordonnée de chaque angle.
La flèche n'apparait pas car elle est masqués.
Il existe aussi la fonction showturtle() pour réafficher la flèche.
Plutôt que d'utiliser les fonctions forward(), backward() left(), right() nous allons utiliser la fonction goto(x,y). qui est beaucoup plus intiutive et plus mathématique.
Pour utiliser la fonction goto() il faut bien avoir en tête qu'un repèren cartésien (mais masqué) divise la fenêtre
en 4 zones comme le rappelle le croquis ci-dessous :
Un point situé à gauche de l'axe des Y et sous l'axe des X a donc des coordonnées négatives !
Ce programme utilise un fonction et un boucle afin de réduire sensiblement le nombre de lignes.
def carre(d):
up()
goto(-d,-d)
down()
goto(d,-d)
goto(d,d)
goto(-d,d)
goto(-d,-d)
up()
# ----------fin fonction
# nom programme : tortue_goto.py
from turtle import *
pen()
setup(500,500)
speed('slow')
for cote in range(240,0,-40) :
carre(cote)
print(cote)
home()
down()
write ("hello !", font=("Arial", 14, "normal"))
mainloop()
Notez la fonction nommée "carre()" qui est appelée 6 fois via une boucle.
Si je n'avais pas utilisé de boucle et de fonction le programme serait beaucoup plus long : 40 lignes de plus.
Donc avec un peu d'astuce les programmes turtle ne sont pas trop verbeux.
Le texte est affiché dans le centre de la fenêtre ; home() équivalent à goto(0,0)
Dans le shell affichage des valeurs successives de cote (côté du carré).
Je vous montre aussi comment écrire du texte dans la fenêtre turtle.
setup(800,800)
pen()
hideturtle()
title("Appel du 18 juin 1940")
bgpic("degrade.png")
fillcolor('white')
speed('slow')
pensize(1)
up()
goto(50,350)
begin_fill()
down()
goto(-50,350)
...
goto(50,350)
end_fill()
up()
home()
down()
write ("Appel du 18 juin 1940 par le Général de Gaulle", align ="center", \
font=("Arial", 24, "normal"))
mainloop()
La fonction bgpic("chemin image") permet de remplir le fond de la fenêtre turtle avec une image.
Cette image doit être au format GIF ou PNG.
Ce degradé est un document SVG (image vectorielle) exporté au format PNG.
La fonction write() permet d'écrire dans la fenêtre turtle.
Je vous laisse compléter ce code : une série de goto() ; faites avant un croquis sur une feuille à petits carreaux
(5 carreaux = 100px).
Le module tkinter fait partie de la bibliothèque de base de Python.
Il est surtour destiné à créer de belles interfaces utilisateurs car les entrées et sorties dans le shell c'est pas terrible ...
Cependant il est aussi possible de dessiner avec tkinter.
Le rendu graphique est désormais instantané ; on ne voit plus la progression du dessin par le crayon.
Dessiner lignes, rectangles et polygones.
# canvas1.py from tkinter import * fen = Tk() # définition et affichage d'un canevas canevas = Canvas(fen,width = 600, height = 600) canevas.pack() # dessin d'une ligne canevas.create_line(0,0,600,600) # dessin d'un rectangle canevas.create_rectangle(300,300,500,600) # dessin d'un carré rempli de rouge canevas.create_rectangle((50,50),(110,110), fill ='red', outline ='') # dessin d'un polygone canevas.create_polygon((400,400),(600,400),(600,600),fill ='', outline ='red', width =3)
from tkinter import * : il faut importer le module tkinter.
fen = Tk() : puis on crée une instance de la classe Tk que l'on nom "fen" (comme fenêtre) car l'objet tk crée une fenêtre.
canevas = Canvas(fen,width = 600, height = 600): définition d'une zone de dessin (ou "canevas")
de 500 par 500 pixels via la méthode Canvas().
canevas.pack() : affichage du canevas (objet de type Canvas) dans la fenêtre tkinter
Dessiner une ligne oblique :
canevas.create_line(0,0,600,600):
il faut appliquer à la méthode create_line() les coordonnées x,y du point départ et coordonnées x,y du point d'arrivée.
Pour réaliser la même ligne avec turtle il y aurait eu plusieurs instructions ...ici une seule !
Attention l'origine du canevas n'est plus son centre (comme avec une fenêtre turtle) mais le coin haut gauche de cette zone de dessin.
Dessins de rectangles et carrés :
canevas.create_rectangle(300,300,500,600) : dessin d'un rectangle avec la méthode create_rectangle(x1,y1,x2,y2)
Les arguments sont les coordonnées du coin supérieur gauche puis les coordonnées x,y du coin inférieur droit.
Donc les deux derniers arguments ne sont surtout pas les largeur et hauteur du rectangle.
canevas.create_rectangle((50,50),(110,110), fill ='red', outline ='') :
dessin d'un carré de largeur 60 (110-50) et de hauteur 60 (110-50) rempli de rouge et sans bordure.
Dessin d'un polygone :
canevas.create_polygon((400,400),(600,400),(600,600),fill ='', outline ='red', width =3) :
dessin d'un triangle non rempli avec une bordure rouge de 3px d'épaisseur.
Pour une meilleure lisibilité regrouper chaque couple de coordonnées dans un tuple.
Le graphique s'affiche dans une fenêtre avec par défaut le titre "tk".
Dans tkinter le rendu graphique est instantané alors que dans turtle on voit le crayon réaliser
progressivement le dessin.
# canvas2.py
from tkinter import *
fen = Tk()
fen.title("Cercles, ellipses, arcs")
# canevas de 400 par 700
canevas = Canvas(fen,width = 400, height = 700)
canevas.pack()
# ellipse
canevas.create_arc(50,50,250,150,extent = 359, style = ARC, outline ="black", width ="3")
canevas.create_text(200,30, /
text ="Une ellipse : arc de 359° qui s'inscrit dans un rectangle", font =('Times',12))
# cercle
canevas.create_arc(200,200,400,400,extent = 359, style =ARC, outline ="red", width ="3" )
canevas.create_text(180,200, /
text ="Un cercle : arc de 359° qui s'inscrit dans un carré",anchor="w", font =('Times',12) )
# arc d'ellipse haut
canevas.create_arc(100,400,300,500,extent = 180, style = ARC, outline ="green", width ="3")
canevas.create_text(50,380, /
text ="Arc d'ellipse haut : extent inférieur à 359",anchor="w",font =('Times',12) )
# arc de cercle bas
canevas.create_arc(100,500,300,700,extent = -180,style =ARC, outline ="blue", width ="3")
canevas.create_text(200,480, /
text ="Arc de cercle bas : extent est négatif", anchor ="center",font =('Times',12) )
# segment de corde
canevas.create_arc(100,500,300,700,extent = -180,style =CHORD, outline ='', fill ='navy')
canevas.create_text(250,580, /
text ="Segment de corde", font =('Times',12) )
fen.mainloop()
fen.title("Cercles, ellipses, arcs") : je personnalise le titre de la fenêtre tkinter.
La méthode create_arc() permet de dessiner des ellipses, cercles, arcs de cercle ou d'ellipse, segments de corde, secteurs.
canevas.create_text(200,30, text ="Une ...", font =('Times',12)) :
on peut afficher du texte dans un canevas avec la méthode create_text(x,y, text = ...,font=(...))
par défaut anchor = 'center' ce qui veut dire que le texte se répartit par rapport aux coordonnées x,y.
Notez les valeurs de l'attribut font : utilisation de la police "Times New Roman" avec une taille de 12
c'est très facile de créer un dessin animé avec Python-tkinter.
#canvas3.py
from tkinter import *
import time
fen = Tk()
fen.title("Canevas animé")
fen.geometry("600x600")
fen.config(bg ="skyblue")
canevas = Canvas(fen, width = 500, height = 500,bg='lime')
canevas.pack()
tricolore = canevas.create_oval(200,200,300,300, fill ="red" , outline ='')
while True :
liste = ['green','orange','red']
for i in (range(0,3)):
couleur = liste[i]
canevas.itemconfig(tricolore,fill =couleur)
fen.update()
time.sleep(5)
fen.mainloop()
La boule au centre du canevas change de couleur de remplissage toutes les 5 secondes : vert puis orange puis rouge et de nouveau vert ...
Pour dessiner des cercles et des ellipses complètes il y a plus simple que create_arc() : la méthode create_oval(). Ici je dessine un cercle car l'ovale est inscrit dans un carré de 100 par 100.
Bien évidemment l'animation illimitée n'est pas rendue par cette capture d'écran.
On voit bien la différence entre la fenête tkinter (bleu ciel) et l'objet Canvas (vert clair).
#canvas4.py
from tkinter import *
fen = Tk()
fen.title("Les dents de la mer")
fen.geometry("600x400")
fen.config(bg ="skyblue")
canevas = Canvas(fen, width = 600, height = 400)
canevas.pack()
fond = PhotoImage(file ='fond.png')
canevas.create_image(0,0,anchor =NW, image = fond)
sprite = PhotoImage(file ='plongeur2.gif')
canevas.create_image(0,0,anchor =NW, image = sprite)
requin = PhotoImage(file ='requin.gif')
canevas.create_image(400,300,anchor =NW, image = requin)
fen.mainloop()
fond = PhotoImage(file ='fond.png') : chargement de l'image ; la fonction n'accepte que les formats GIF & PNG.
canevas.create_image(0,0,anchor =NW, image = fond) : le coin supérieur gauche de l'image (anchor = NW) est positionnée
dans le coin haut gauche du canevas.
Il n'est pas possible de redimensionner l'image insérée via la fonction create_image() ...
Comme l'image "fond.png" fait 600 par 400, elle occupe tout le canevas.
Deux autres images sont insérées au dessus ; elles ont été redimensionnées auparavant avec Paint.
Turtle et tkinter se complètent. Il est plus facile de dessiner un polygone à 5 côtés (ou plus), une étoile à N branches
avec turtle qu'avec tkinter.
Par contre c'est très compliqué de dessiner une ellipse avec turtle alors que c'est un jeu d'enfant avec tkinter.
On peut réaliser des animations graphiques avec tkinter voire des jeux vidéo basiques ...