Accueil
Mes tutoriels sur la programmation

Tutoriel Python - sommaire


Vous pouvez me contacter via Facebook (questions, critiques constructives) : page Facebook relative à mon site

Le module Tkinter

Nous avons déjà réalisé de nombreux programmes avec des traitements de plus en plus complexes. Mais nos entrées et sorties avec les fonctions input() & print() sont toujours "tristounettes" ...

Le module Tkinter nous permet de réaliser d'agréables interfaces graphiques entre l'utilisateur et le programme.

Tkinter est un module intégré à la bibliothèque standard de Python. Donc nul besoin de télecharger une extension. Il faut simplement l'importer.
En fait avec ce module nous créons une fenêtre comprenant des éléments ou "widgets" : cadres, zones de texte, cases à cocher, boutons radio, zone de listes, boutons de commande, etc.
Nous allons découvrir ce module via des programmes de plus en plus complexes.

Premier programme

Le code

# nom programme : test_tkinter0.py
from tkinter import *

# Création d'un objet "fenêtre"
fenetre = Tk()  	# nouvelle instance de Tk
fenetre.title("Connexion ")
fenetre.geometry("600x400")

# pour saisir identifiant
label1 = Label(fenetre, text = "Votre identifiant  ? ")
champ1 = Entry(fenetre, width=30)
label1.pack()
champ1.pack()

# pour saisir identifiant
label2 = Label(fenetre, text = "Votre mot de passe ? ")
champ2 = Entry(fenetre, width=30)
label2.pack()
champ2.pack()

# Bouton de commande 
bouton1 = Button(fenetre, text = "connexion")
bouton1.pack()

fenetre.mainloop()

Il faut importer le module tkinter.
On crée une fenêtre, pour cela, on crée une instance de classe tk que l'on nomme "fenetre".
Puis on attribue à cette fenêtre un titre et une taille par défaut.

Les lecteurs qui connaissent les formulaires HTML, ne seront pas surpris ...
Il faut toujours associer un "label" à un "entry" pour préciser à l'utilisateur ce qu'il doit saisir.

Analyse des instructions du programme

label1 = Label(fenetre, text = "Votre identifiant ? ") : définition d'une étiquette à l'intérieur de l'objet " parent. Il faut utiliser la méthode Label() avec deux arguments au moins : l'objet parent, le texte de l'étiquette.

champ1 = Entry(fenetre, width=30) : définition d'une zone de texte à l'intérieur de l'objet parent. Il faut utiliser la méthode Entry() avec deux arguments au moins : l'objet parent (ici "fenetre") puis la largeur du champ (en pixels).

bouton1 = Button(fenetre, text = "connexion") : définition d'un bouton de commande à l'intérieur de l'objet parent. Il faut utiliser la méthode Button() avec au moins deux arguments : l'objet parent, le texte du bouton.

label1.pack() : positionner l'élément "label1" dans la fenêtre.
Il y a 5 widgets donc il y a donc cinq commandes de type pack.

fenetre.mainloop() : crée une boucle infinie dont on ne sortira que lorsque l'on fermera la fenêtre.

Attention à la "casse".
Les méthodes du module sont sensibles à la casse. Ainsi pour créer une étiquette il faut saisir Label (avec un L majuscule) et pour définir une zone de texte il faut écrire Entry (avec un E majuscule).

Le rendu de ce programme

tutoriel tkinter

Deuxième programme

Le code

# nom programme : test_tkinter1.py
# objet : présentation de widgets moins connus
from tkinter import *

# Création d'un objet "fenêtre"
fenetre = Tk()  # nouvelle instance de Tk
fenetre.title("Fiche de renseignements")
fenetre.geometry("900x600")
fenetre.minsize(300, 200)
fenetre.config(bg ="skyblue")
for i in range(1,6):
    fenetre.rowconfigure(i, pad =15)

# spinbox
e1 = Label(fenetre, text = "Votre âge ?  ")
spinbox1 = Spinbox(fenetre, from_=20, to=90, increment=1)
e1.grid(row =1, column =1)
spinbox1.grid(row =1, column =2)

#scale
e2 = Label(fenetre, text = "Votre poids ?  ")
scale1 = Scale(fenetre, from_=40, to=100, showvalue=True, label='kilos' ,orient='h')
e2.grid(row =2, column =1)
scale1.grid(row =2, column =2)

#radiobutton ; rd
e3 = Label(fenetre, text = "Votre sexe ?  ")
rb1 = Radiobutton(fenetre, text="femme" , value ="f")
rb2 = Radiobutton(fenetre, text="homme", value ="m")
e3.grid(row =3, column =1)
rb1.grid(row =3, column =2)
rb2.grid(row =3, column =3)

#checkbutton ; cc
e4 = Label(fenetre, text = "Jeux de cartes pratiqués  ?  ")
cc1 = Checkbutton(fenetre, text="belote")
cc2 = Checkbutton(fenetre, text ="tarot")
cc3 = Checkbutton(fenetre, text ="bridge")
e4.grid(row =4, column =1)
cc1.grid(row =4, column =2)
cc2.grid(row =4, column =3)
cc3.grid(row =4, column =4)

e5 = Label(fenetre, text = "sport premier pratiqué  ?  ")
items =Variable(fenetre, ("aucun", "tennis", "vélo", "foot", "natation", "autre"))
liste1 = Listbox(fenetre, listvariable=items)
e5.grid(row =5, column =1)
liste1.grid(row =5, column =2)

fenetre.mainloop()

Commentaire

Il y a beaucoup de nouveautés dans ce programme.
Passons les en revue.

fenetre.geometry("900x600") : dimensions par défaut de la fenêtre.

fenetre.config(bg ="skyblue") : définition d'une couleur de fond pour la fenêtre.

for i in range(1,6):
____fenetre.rowconfigure(i, pad =15)
 : pour les 5 lignes de la grille de positionnement on définit une marge externe de 15 pixels.
Ainsi les widgets ne seront pas collés car sinon la hauteur d'une ligne est égale à celle du widget le plus haut dans la ligne.
Par défaut la largeur d'une colonne est égale à celle du widget le plus large dans la colonne. Il existe aussi la méthode columnconfigure pour produire un espacement vertical.

spinbox1 = Spinbox(fenetre, from_=20, to=90, increment=1) : un "spinbox" permet de sélectionner une valeur de l'intervalle défini en cliquant sur des flèches. Mais si l'intervalle est large, la saisie dans ce type de widget devient fastidieuse.

e1.grid(row =1, column =1) : cette étiquette est placée dans la cellule L1C1 de la grille.

scale1 = Scale(fenetre, from_=40, to=100, showvalue=True, label='kilos' ,orient='h') : un widget de type "scale" permet de sélectionner rapidement une valeur de l'intervalle défini. Ici la valeur sélectionnée est affichée et le widget "scale" est dans l'exemple, orienté horizontalement.

rb1 = Radiobutton(fenetre, text="femme", value="f") : définition d'un bouton radio.
Il y a un deuxième bouton radio. Dans un groupe de boutons radio, un seul peut être coché.

cc1 = Checkbutton(fenetre, text="belote") : définition d'une case à cocher.

liste1 = Listbox(fenetre, listvariable=items) : définition d'une "listbox" (zone de liste). Cette liste est construite à partir du tuple contenu dans la variable "items".

Retenons de cet exemple, que la méthode grid() permet le positionnement sur une grille.
Qu'en plus des étiquettes et des zones de texte il existe d'autres types de widgets : "spinbox", "scale", case à cocher, bouton radio, zone de liste.

Le rendu

tutoriel tkinter

Observez bien l'apparence d'un widget de type "spinbox" (toupie) et "scale" (échelle / curseur). Ceux-qui connaissent bien les formulaires HTML ne seront pas surpris. On a le même rendu avec en HTML les instructions : input type ="number" & input type ="range"

Les frames

On peut diviser la fenêtre en différentes zones appelés "frames" (cadres).
Chaque cadre contient des éléments.

Thème : page d'accueil d'une application pour laquelle l'utilisateur doit être inscrit.
L'utilisateur doit donc se connecter ou s'inscrire, si c'est sa première visite.

Le code

 
# nom programme : test_tkinter4.py
# objet : fenêtre avec deux frames
from tkinter import *

# Création d'un objet "fenêtre"
fenetre = Tk()  # nouvelle instance de Tk
fenetre.title("Connexion / inscription ")
fenetre.geometry("900x600")
fenetre.config(bg ="white")

f1 =LabelFrame(fenetre,bd=2, text ="connexion", bg ="skyblue", relief="groove")
f2= LabelFrame(fenetre,bd=2, text ="inscription", bg ="skyblue", relief="groove")
f1.pack(side =LEFT, padx =20, pady=20)
f2.pack(side =RIGHT,padx =20, pady=20)

e1 = Label(f1, text ="identifiant  ? ").pack(padx =20, pady=20)
zt1 = Entry(f1,width =50).pack(padx =20, pady=20)
e2 = Label(f1, text ="mot de passe ?  ").pack(padx =20, pady=20)
zt2 = Entry(f1,width =50).pack(padx =20, pady=20)

e3 = Label(f2, text ="identifiant ?  ").pack(padx =20, pady=20)
zt3 = Entry(f2,width =50).pack(padx =20, pady=20)

e4 = Label(f2, text ="confirmer identifiant ! ").pack(padx =20, pady=20)
zt4 = Entry(f2,width =50).pack(padx =20, pady=20)

e5 = Label(f2, text ="mot de  passe ? ").pack(padx =20, pady=20)
zt5 = Entry(f2,width =50).pack(padx =20, pady=20)

e6 = Label(f2, text =" confirmer mot de  passe !  ").pack(padx =20, pady=20)
zt6 = Entry(f2,width =50).pack(padx =20, pady=20)

fenetre.mainloop()

Analyse du code

Vous trouvez sans doute que le code est un peu lourd. Mais en fait il se produit très rapidement car il y a 6 étiquettes et 6 zones de texte pratiquement identiques pour leurs arguments donc n'hésitez pas dans les "copier/coller".

f1 =LabelFrame(fenetre,bd=2, text ="connexion", bg ="skyblue", relief="groove") : définition d'un cadre, enfant de "fenetre", borduré avec l'étiquette "connexion", couleur de fond : "skyblue".
Il existe aussi la méthode frame() mais qui ne prévoit pas d'étiquette.
f1.pack(side =LEFT, padx =20, pady=20) : le frame "f1" est positionné à gauche avec des marges par rapport à son parent : "fenetre".
e1 = Label(f1, text ="identifiant ? ").pack(padx =20, pady=20) : chainage de deux méthodes pour définir une étiquette enfant de "f1" et la positionner avec des marges par rapport au parent.

Le rendu

tutoriel tkinter

Récupérer dans une fonction les saisies dans des champs

Arrivé à ce stade, vous devez vous dire : c'est bien gentil tout ça. Mais à quoi ça sert puisqu'il n'y a aucun traitement des données saisies.
Je n'ai pas voulu aborder de front le code découlant du design et celui qui permet de transférer des données de l'interface vers le programme et vice-versa.
J'ai évoqué le "front-end" et maintenant je vais aborder le "back-end".

Thème : via une interface l'utilisateur saisit x et n dans des champs et en retour il y a affichage de x à la puissance n dans un troisième champ.
Une fonction doit donc être capable de récupérer les saisies dans des zones de texte et injecter le résultat dans une troisième ...

Le code

# nom programme : test_tkinter3.py
# objet du programme : élever x à la puisssance n
from tkinter import *
from math import *

def fpuissance():
    x = zt1.get()
    n = zt2.get()
    resultat = pow(eval(x), eval(n))
    zt3.delete(0,END)
    zt3.insert(0,resultat)

# ------ fin fonction

# Création d'un objet "fenêtre"
fenetre = Tk()  # nouvelle instance de Tk
fenetre.title("Elever x à la puissance n ")
fenetre.geometry("400x400")

fenetre.config(bg ="lime")
for i in range(1,5):
    fenetre.rowconfigure(i, pad =20)
fenetre.columnconfigure(1,pad = 20)
fenetre.columnconfigure(2, pad =20)

# pour saisir x

e1 = Label(fenetre, text = " valeur de x ? ")
e1.grid(row=1, column=1)
zt1 = Entry(fenetre, width=30)
zt1.grid(row=1, column=2)

# pour saisir n

e2 = Label(fenetre, text = "valeur de n  ?  ")
e2.grid(row=2, column=1)
zt2 = Entry(fenetre, width=30)
zt2.grid(row=2, column=2)

# Bouton de commande 
b1 = Button(fenetre, text = "Calcul", command=fpuissance)
b1.grid(row=3, column=2)

# pour afficher le résultat
e3 = Label(fenetre, text = "x à la puissance n  = ")
e3.grid(row=4, column=1)
zt3 = Entry(fenetre, width=30)
zt3.grid(row=4, column=2)

fenetre.mainloop()

Analyse du code

Les "Entry" se nomment zt1, zt2 et zt3.

Un objet de type "Button" peut avoir comme argument "command =nomFonction"
Le code du programme principal ne présente aucune difficulté c'est seulement du design donc une syntaxe déja vue.
Ici le bouton de commande appelle la fonction "fpuissance".

Étudions le code de cette fonction qui comprend toutes les nouveautés :
x = zt1.get() : récupération du contenu du champ "zt1"
resultat = pow(eval(x), eval(n)) : x et n sont convertis en numérique avant d'être les arguments de la méthode pow(). N'oubliez pas d'importer le module math.
zt3.delete(0,END) : effacer le contenu du champ "zt3"
zt3.insert(0,resultat) : insertion du contenu de la variable resultat dans le champ "zt3"

Le rendu

tutoriel tkinter

Si l'utilisateur saisit, par exemple, 10,5 dans le premier champ c'est alors considéré par Python comme un tuple et non une chaine numérique. La conversion par la fonction eval() est alors impossible.
On aurait moins de risque d'erreur si les zones de saisie étaient des widgets de type "spinbox" ou "scale".

Exercice : une calculatrice basique

Le meilleur moyen de vérifier si vous avez bien assimilé tout ce que je viens de dire, c'est de réaliser vous même un programme avec une UI (User Interface).
Par exemple une calculatrice basique : les 5 opérations de base : addition, multiplication, soustraction, division, élévation à la puissance.

Ce que vous devez obtenir

tutoriel tkinter

Extrait du programme

Je vous communique cependant une partie du programme car j'en profite pour vous montrez comment créer une fenêtre non redimensionnable et aussi comment personnaliser les légendes des widgets.
Ci-dessous début du programme principal :

#programme principal
from tkinter import *
# Création d'une interface graphique
fenetre = Tk()  # nouvelle instance de Tk
fenetre.title("Calculatrice ")
fenetre.geometry("900x300")
fenetre.resizable(False, False) #  l'interface n'est pas redimensionnable
fenetre.config(bg ="lime")
for i in range(1,6):
    fenetre.rowconfigure(i, pad =10)
for i in range(1,5):
    fenetre.columnconfigure(i, pad =15)
mafonte = "{courier new} 14"
...
# pour saisir A
e1 = Label(fenetre, text = " saisir A", font =mafonte)
zt1 = Entry(fenetre, width=15,font =mafonte)
...

Notez l'instruction fenetre.resizable(False, False) : La fenêtre ne peut être redimensionnée ni en hauteur, ni en largeur.
mafonte = "{courier new} 14" : je définis un objet "font" dénommée "mafonte".
e1 = Label(fenetre, text = " saisir A", font =mafonte) : à chaque widget j'ajoute l'option "font = mafonte" afin que la taille des textes soit plus grande.
zt1 = Entry(fenetre, width=15,font =mafonte) : évitez des champs de saisie trop larges.

Récupérer les saisies via des boutons radio, case à cocher et zones de liste

Dans l'exemple précédent nous avons récupéré dans une fonction les contenus de deux zones de texte (champs) via la méthode get().
Pour récupérer les saisies effectuées dans des widgets de type cases à cocher, boutons radio et zones de liste c'est un peu plus compliqué. Le programmeur doit utiliser des variables spécifiques à tKinter dites variables de contrôle.

Variables de contrôle

Le code

# nom programme : test_tkinter5.py
# objet : traitement d'un groupe de boutons radio, cases à cocher, liste
def  mafonction():
    monpoids = vc1.get()
    monsexe =vc2.get()
    belote = vc3.get()
    tarot = vc4.get()
    bridge = vc5.get()
    print ("mon poids :", monpoids)
    print("mon sexe : ", monsexe)
    print("belote : ", belote)
    print("tarot : ", tarot)
    print("bridge : ", bridge)
    index = liste1.curselection()
    item= liste1.get(index)
    print ("sport : ", index, item)

# programme principal avec design de la fenêtre
from tkinter import *
# définition de la fenêtre
fenetre = Tk()  # nouvelle instance de Tk
fenetre.title("Fiche de renseignements")
fenetre.geometry("900x600")
fenetre.config(bg ="skyblue")
for i in range(1,6):
    fenetre.rowconfigure(i, pad =20)

# un scale
vc1 =  IntVar()
e2 = Label(fenetre, text = "Votre poids ?  ")
scale1 = Scale(fenetre, from_=40, to=100, showvalue=True, label='kilos' ,orient='h', variable =vc1)
e2.grid(row =2, column =1)
scale1.grid(row =2, column =2)

# deux radiobutton
vc2 =StringVar()
e3 = Label(fenetre, text = "Votre sexe ?  ")
rb1 = Radiobutton(fenetre, text="femme" , value ="féminin", variable = vc2)
rb2 = Radiobutton(fenetre, text="homme", value ="masculin",variable =vc2)
e3.grid(row =3, column =1)
rb1.grid(row =3, column =2)
rb2.grid(row =3, column =3)

# trois cases à cocher
vc3 =IntVar()
vc4 =IntVar()
vc5 =IntVar()
e4 = Label(fenetre, text = "Jeux de cartes pratiqués  ?  ")
cc1 = Checkbutton(fenetre, text="belote", variable =vc3)
cc2 = Checkbutton(fenetre, text ="tarot",variable =vc4)
cc3 = Checkbutton(fenetre, text ="bridge",variable =vc5)
e4.grid(row =4, column =1)
cc1.grid(row =4, column =2)
cc2.grid(row =4, column =3)
cc3.grid(row =4, column =4)

# une zone de liste
e5 = Label(fenetre, text = "sport premier pratiqué  ?  ")
items =Variable(fenetre, ("aucun", "tennis", "vélo", "foot", "natation", "autre"))
liste1 = Listbox(fenetre, listvariable=items)
e5.grid(row =5, column =1)
liste1.grid(row =5, column =2)

#  un bouton de commande 
bouton1 = Button(fenetre, text = "Récupérez les valeurs saisies", command=mafonction)
bouton1.grid(row=6, column=2)

fenetre.mainloop()

Notez que la fonction comprend des instructions "print". Donc les sorties se feront dans la fenêtre Shell de l'IDLE.

Le rendu

L'interface graphique

tutoriel tkinter

La fenêtre Shell de l'IDLE

mon poids : 68
mon sexe :  masculin
belote :  0
tarot :  1
bridge :  0
sport :  (4,) natation

Analyse du code

Commençons par le programme principal

Nous déclarons 5 variables de contrôle nommées "vc1, ... vc5".
"vc1" est relié au widget "scale" et mémorise un entier.
scale1 = Scale(fenetre, from_=40, to=100, showvalue=True, label='kilos' ,orient='h', variable =vc1) : dans les arguments de Scale() j'ai rajouté "variable =vc1".

"vc2" est relié au groupe de boutons radio et mémorise une chaine.
rb1 = Radiobutton(fenetre, text="femme" , value ="féminin", variable = vc2) : pour les boutons radio "rb1" et "rb2" j'ai rajouté dans la méthodeRadiobutton() l'argument "variable =vc2"

Notez bien que pour chaque bouton radio il y a l'argument "value = valeur". Donc si vous sélectionnez "rb1" vous saisissez en fait "féminin" et si vous sélectionnez "rb2" vous saisissez "masculin".

Il y a trois cases à cocher, il faut donc définir trois variables de contrôle qui mémorise un entier (1 ou 0 selon que la case est cochée ou pas) : "vc3, vc4, vc5"
cc1 = Checkbutton(fenetre, text="belote", variable =vc3) : dans chacun des trois cases à cocher je rajoute dans les arguments de Ckeckbutton() : "variable = nomVariableControle".

bouton1 = Button(fenetre, text = "Récupérez les valeurs saisies", command=mafonction) :
sur clic sur le bouton de commande j'appelle la fonction "mafonction".

Analyse de cette fonction

Il faut récupérer les valeurs de contrôle dans des variables de la fonction.
monpoids = vc1.get() : récupération du contenu de "vc1" dans variable de fonction "monpoids"
monsexe =vc2.get() : récupération du contenu de "vc2" dans variable de fonction "monsexe"
belote = vc3.get(): récupération dans vc3 de 1 ou zéro. Même remarque pour vc4 et vc5

index = liste1.curselection() : si, dans la liste, j'ai sélectionné la cinquième ligne, la variable "index" récupère 4 grâce à la méthode curselection().
item= liste1.get(index) :la variable "item" récupère l'item d'indice 4 donc "natation".

Amélioration du programme

Tout ça c'est bien mais perfectible.
Pour les jeux de cartes pratiqués, à la place des 1 ou zéro (coché ou décoché) on préferait une chaine du genre : tarot bridge
Les informations saisies doivent s'afficher dans une zone de texte de l'interface.
La taille des caractères doit être plus grande avec de la graisse.

Extrait du programme principal modifié

...
mafonte = "{courier new} 10 bold "
...
e1 = Label(fenetre, text = "Fiche de renseignements ", font = mafonte)
e1.grid(row =1, column =2)
...
scale1 = Scale(fenetre, from_=40, to=100, showvalue=True, label='kilos' ,orient='h', variable =vc1, font=mafonte)
...
# trois cases à cocher
vc3 =StringVar()
vc4 =StringVar()
vc5 =StringVar()
e4 = Label(fenetre, text = "Jeux de cartes pratiqués  ?  ")
cc1 = Checkbutton(fenetre, text="belote", onvalue = "belote", variable =vc3)
cc2 = Checkbutton(fenetre, text ="tarot",onvalue ="tarot", variable =vc4)
cc3 = Checkbutton(fenetre, text ="bridge", onvalue = "bridge",variable =vc5)
...
# pour afficher le résultat
e6 = Label(fenetre, text = "vos informations   : ")
e6.grid(row=6, column=1)
zt1 = Entry(fenetre, width=40)
zt1.grid(row=6, column=2)

Commentaire

mafonte = "{courier new} 12 bold " : je définis un objet "fonte".
e1 = Label(fenetre, text = "Fiche de renseignements ", font = mafonte) : à chaque widget j'ajoute l'option font = mafonte.

Pour chaque case à cocher, j'ai rajouté un argument à la méthode checkbutton(). Exemple : onvalue = "belote"
Donc si la case est cochée la valeur retournée n'est plus 1 mais la valeur de l'argument onvalue.
Donc les trois variables de contrôle associées aux "Checkbutton" doivent changer de type puisqu'elles doivent désormais retourner une chaine.

zt1 = Entry(fenetre, width=40, font =mafonte) : ajout d'une zone de texte large (40px) qui va afficher la chaine retournée par la fonction.

Extrait de la fonction modifié (dernières lignes)

...
	resultat = str(monpoids) + " " + " " +  monsexe +" " + belote + " " + tarot + " "+ " " + bridge + " " + item
    zt1.delete(0,END)
    zt1.insert(0,resultat)

Les variables "belote", "tarot", "bridge" contiennent désormais une chaine ou zéro (si case non cochée).

Le rendu

tutoriel tkinter

Il aurait été judicieux d'utiliser pour les cases à cocher l'option "offvalue" également.
Dans chacune des trois "Checkbutton" on rajoute :Checkbutton( ... , offvalue =" ", ...) . Ainsi si la case en question n'est pas cochée on récupère une chaine vide.

Dessiner dans une interface graphique

Avec la méthode Canvas() vous pouvez créer dans une fenêtre une zone de dessin.
Ce canevas peut comprendre des formes géométriques mais aussi des images matricielles.
Un canevas est un rectangle ayant pour origine le coin supérieur gauche.

Si vous connaissez JavaScript et son API Canvas (qui est implémenté par les tous les navigateurs récents) vous serez très vite familiarisé avec les canevas de Tkinter.

Un programme qui crée un canevas

Dans la fenêtre je dessine un canevas et j'insère dedans un image GIF et du texte au dessus de l'image.
L'image doit être centrée dans le canevas, ses dimensions : celles du canevas /2.

Le code du programme

# nom programme : test_canvas1.py
from tkinter import *
# définition de la fenêtre
fenetre = Tk()  # nouvelle instance de Tk
fenetre.geometry("600x400")
fenetre.config(bg ="skyblue")
fenetre.title("Insertion d'un canevas dans la fenêtre")
w = 300
h =300
mafonte = "{courier new} 14 bold "

#  insertion d'un canevas
canevas = Canvas(fenetre, width=w, height=h, bg='yellow')
monGif = PhotoImage(file="ordinateur.gif")
# cette image est dans le même dossier que le fichier.py
canevas.create_image(w/2, h/2, image=monGif)
#  l'objet de type "Canvas" est stocké dans la variable 'canevas'
canevas.create_text(w/2, h/2, text="Tkinter, c'est super !", font =mafonte, fill="navy")
canevas.pack()

fenetre.mainloop()

Analyse

canevas = Canvas(fenetre, width=w, height=h, bg='yellow') : création d'un objet de type "Canvas" dans la fenêtre et qui est stocké dans la variable "canevas". Trois arguments obligatoires : parent, width, height).
monGif = PhotoImage(file="ordinateur.gif") : sélection de l'image gif à insérer avec la méthode PhotoImage(file =chemin de l'image)
canevas.create_image(w/2, h/2, image=monGif) : insertion dans le canevas de l'image avec la méthode create_image(). Les arguments sont : X, Y, image. X et Y sont les coordonnées de l'ancrage.
Par défaut l'image est centrée par rapport à ce point d'ancrage (anchor ="center")
canevas.create_text(w/2, h/2,text="Tkinter, c'est super !", font =mafonte, fill="navy") : insertion dans le canevas d'un texte. Les attributs obligatoires sont : X, Y et text. X et Y sont les coordonnées du point d'ancrage.
Par défaut le texte est centré par rapport à ce point d'ancrage (anchor ="center").

L'attribut anchor peut prendre d'autres valeurs : nw, n,ne,e,se, sw,w c'est à dire les points cardinaux.

Un conseil : les images à insérer et le programme (fichier .py) dans le même répertoire !

Le rendu

tutoriel tkinter

Remarque

On ne se rend pas compte que l'image est deux fois plus petite que le canevas qui la contient ; c'est normal, le format GIF gère la transparence.

Attention l'insertion d'un GIF, comme le montre l'exemple ci-dessus, ne pose pas de difficulté, par contre pour les autres formats d'images matricielles, c'est un peu plus délicat ...
Si vous insérez un gif animé dans un canevas, l'image reste fixe à moins de créer une boucle qui anime chaque image constitutive du gif animé.
Pour insérer, dans un canevas, des images d'autres formats (.jpeg, png), il faudra passer par le module PIL (qui n'est pas présent par défaut dans Python).

Dessiner des formes dans un canevas

Des méthodes

Thème : Uu programme qui dessine dans un canevas le logo de l'entreprise.

Le code

# nom programme : test_canvas2.py
#fenetre avec logo de l'entreprise 
from tkinter import *
# définition de la fenêtre
fenetre = Tk()  # nouvelle instance de Tk
fenetre.geometry("900x600")
fenetre.config(bg ="skyblue")
fenetre.title("Insertion d'un canevas dans la fenêtre")
# dimensions minimales des ligne et colonne zéro
fenetre.rowconfigure(0,minsize =30)
fenetre.columnconfigure(0,minsize =30)
w = 250
h =150
mafonte = "arial 12 bold "
#  insertion d'un canevas
canevas = Canvas(fenetre, width=w, height=h)
rect1 = canevas.create_rectangle(0, 0, w, h, fill ="blue")
canevas.create_oval(w/10, h/10, w*9/10, h*9/10, fill ="red", outline ="white", width =8)
canevas.create_text(w/2, h/2, text="Francemeubles.com", font =mafonte, fill="white")
canevas.grid(row =1, column=1)

Analyse du code

fenetre.rowconfigure(0,minsize =30)
fenetre.columnconfigure(0,minsize =30)
 : la ligne et la colonne 0 ont une largeur / hauteur de 30px. Le canevas va en effet être positionné avec la méthode grid().

Le rectangle occupe tout le canevas et est rempli de bleu.

Une ellipse de fond rouge avec une bordure blanche épaisse se superpose.

Un texte ancré au milieu du canevas a des caractères blancs.

Le rendu

tutoriel tkinter