(site sans réclame)
Python  –  Manuel  –  Cont@ct  –  S'abonner

Module graphique Tkinter pour Python

L

E module graphique de référence de python est Tkinter. Il en existe d'autres: wxPython, PyQt ou PyGTK. Cette page comporte des répétitions à l'attention des programmeurs pressés qui brûlent les étapes. Les exemples, testés sur GNU/Linux Debian, sont fonctionnels au moins jusqu'à python 2.7.

Cette page a été écrite en 2007, avec corrections et ajouts en ces mois de mai, juin et août 2014.

1. Utilisation du module Tkinter

Tout d'abord, le module Tk pour python doit être installé. Pour Debian-Lenny, Squeeze ou Wheezy:

apt-get install python-tk

Attention: lors de l'installation sous Debian Wheezy, il a fallu un reboot pour que les scripts ci-dessous fonctionnent.

En python3, le paquet nécessaire est python3-tk, du moins avec GNU/Linux Debian.

1.1 Charger le module

Pour utiliser le module Tkinter, il faut d'abord choisir un mode d'importation:

import Tkinter charge le module, dont le nom doit précéder toute méthode ou constante:

#! /usr/bin/python
import Tkinter
racine=Tkinter.Tk()
bouton=Tkinter.Button(racine, text="Quitter", command=racine.quit)
bouton.pack(side=Tkinter.LEFT)
racine.mainloop()

import Tkinter as tk permet d'utiliser un alias: racine=tk.Tk() remplace racine=Tkinter.Tk(). Mais T ou même zzz pourraient faire l'affaire.

from Tkinter import * permet d'utiliser toutes les méthodes ou constantes sans devoir les préfixer:

#! /usr/bin/python
from Tkinter import *
racine=Tk()
bouton=Button(racine, text="Quitter", command=racine.quit)
bouton.pack(side=LEFT)
racine.mainloop()

Par souci de clarté, le module Tkinter sera toujours explicite dans cette page; les variables seront en français et en minuscules.

En python3, le module est rebaptisé tkinter. Il faudra alors choisir un de ces chargements de module:

import tkinter
import tkinter as Tkinter  # pour la compatibilité avec cette page
import tkinter as tk       # pour un préfixage tk
from tkinter import *      # pour éviter tout préfixage

1.2 Ouvrir une fenêtre

L'utilisation d'une fenêtre se résume schématiquement à cette procédure (les majuscules sont toujours importantes):

#! /usr/bin/python
import Tkinter      # pour python3: import tkinter as Tkinter
racine=Tkinter.Tk()
racine.title("Un titre arbitraire")
racine.geometry("400x300")
racine.mainloop()

Tk() permet de désigner un premier objet (une fenêtre) duquel les autres dépendront, le nom (arbitrairement choisi) est déterminé par racine.title(). racine.mainloop() lancera le gestionnaire d'événements. L'essentiel du script (sauf fonctions ou classes) doit se situer entre les deux, cela peut être considéré comme une boucle.
racine.geometry("400x300") précise une taille fixe de fenêtre. Dans le cas contraire, les dimensions de la fenêtre s'adaptent à son contenu, ce qui peut être voulu, ou indésirable.

1.3 Lancer le script

Tous les exemples proposés sur cette page sont fonctionnels. Il y a plusieurs méthodes pour lancer un script écrit en python.

Dans une console

Pour un script essai.py:

python "chemin/exemple.py"

Il est possible de lancer directement un script avec

cd nom-du-repertoire
./essai.py

si l'on place sur la première ligne

#! /usr/bin/python

et qu'on le rend exécutable

chmod 740 essai.py

En cliquant avec le bouton droit de la souris sur un script ayant l'extension .py, il est possible de spécifier l'application python comme lanceur des fichiers .py. Il est cependant préférable, lors du développement, de le lancer dans une console afin de voir les éventuels messages d'erreur.

Par l'interface graphique

Voir la section Lancement du manuel.

2 Les widgets simples

«widget» est paraît-il une contraction de «window gadget». Il s'agit d'éléments simples, comme un titre, un bouton, un texte, un champ éditable... ou plus complexes, comme un système de menu. Lors de la mise en place d'un widget, la récupération de son identifiant dans une variable permet par la suite de le contrôler.

2.1 Label Rév 2014.08

Label permet un affichage simple de texte:

import Tkinter
racine=Tkinter.Tk()
mot1=Tkinter.Label(racine, text="Premier texte\ndans une fenetre")
mot1.pack(side="bottom")
racine.mainloop()

La variable mot1, qui contient l'identificateur du widget, permet par la suite de modifier avec mot1.config(text="Votre prose") ou supprimer le widget avec mot1.pack_forget()

side="bottom" garde le texte au bas de la fenêtre si on l'agrandit.

Label peut également recevoir une image sous format GIF/PNM ou bitmap:

import Tkinter
racine=Tkinter.Tk()
dessin=Tkinter.PhotoImage(file="nomdefichier.gif")
label=Tkinter.Label(image=dessin)
label.pack()
racine.mainloop()

file désigne un nom de fichier, éventuellement avec une adresse précise.

2.2 Text Rév 2014.08

Text définit une plage permettant l'insertion et la manipulation d'un texte.

import Tkinter
racine=Tkinter.Tk()
texte0=Tkinter.Text(racine, width=25, height=5)
texte0.insert("end","bla bla bla")
texte0.pack(side=Tkinter.RIGHT)
racine.mainloop()

width est la largeur de la plage en nombre de caractères, height le nombre de lignes
state="normal" permet l'édition du texte
state="disabled" en interdit l'édition

insert() permet l'insertion à un endroit du texte: "end" à la fin du texte, "insert" à l'endroit du curseur texte, "current" à l'endroit le plus proche du curseur souris.

La variable-retour texte0 permet d'en changer les paramètres ou de supprimer le widget.

Dans pack(), side="right" concerne l'alignement de la plage de texte: en agrandissant la fenêtre, on verra que la plage de texte se situe à droite, même si le texte est aligné à gauche.

2.3 Entry

Entry crée un champ permettant de saisir un texte. Il faut donc prévoir une variable permettant de recevoir le texte saisi.

import Tkinter
racine=Tkinter.Tk()

invite=Tkinter.Label(racine, text='Cliquer et saisir:', width=20, height=3, fg="navy")
invite.pack()

texte0=Tkinter.StringVar() # prevoir la variable pour recevoir le texte saisi
texte0.set("Par défaut")
saisie0=Tkinter.Entry(textvariable=zouin, width=30)
saisie0.pack()

racine.mainloop()

print zouin.get() # affiche le texte saisi a la fermeture de la fenetre

texte0.set() permet de définir une valeur par défaut.

On peut recevoir une valeur numérique entière avec IntVar(), une valeur réelle avec DoubleVar(), qui retourne une valeur entière additionnée de ".0"

2.4 Button

Button définit un bouton cliquable

import Tkinter
racine=Tkinter.Tk()
bouton=Tkinter.Button(racine, text="Quitter", command=racine.quit)
bouton.pack(side=Tkinter.BOTTOM)
racine.mainloop()

side peut également prendre les valeurs LEFT, RIGHT, TOP ou CENTER

width et height déterminent la largeur et la hauteur en caractères, ou en pixels en cas d'utilisation d'une image.

bitmap

Il existe une série d'images toutes faites (pour les nostalgiques des premières icones N/B) pour ces boutons: "error", "gray75", "gray50", "gray25", "gray12", "hourglass", "info", "questhead", "question", "warning", à utiliser de la sorte:

import Tkinter
racine=Tkinter.Tk()
variable43=Tkinter.Button(racine, text="Attention", compound="top", bitmap="warning")
variable43.pack()
racine.mainloop()

compound, qui indique la position de l'icone par rapport au texte, peut prendre la valeur "center" (superposition) ou "none" (escamote le texte).

Il est - heureusement - possible d'utiliser une image bitmap personnelle initialisée avec BitmapImage().

2.5 Checkbutton

Chekbutton est une "case à cocher". Une méthode est proposée pour récupérer l'information sur l'état de la "case à cocher".

#! /usr/bin/python
# -*- coding: utf-8 -*-

import Tkinter
racine=Tkinter.Tk()
retour43=Tkinter.IntVar() # on crée une variable pour l'état de la case à cocher
bouton43=Tkinter.Checkbutton(racine, variable=retour43, text="Cochez-moi")
bouton43.pack()
racine.mainloop()

# pour cet exemple, la valeur est récupérée lors de la sortie de la fenêtre:
if retour43.get(): # la variable 'retour' est à 1 si la case est cochée, à 0 sinon
  print "Tilt!"
else:
  print "Vide!"

Pour forcer un changement dans un script, sans interaction avec la souris (1 pour cochée, 0 pour décochée):

retour43=Tkinter.IntVar(); retour43.set(1)

2.6 Radiobutton Rév 2014.08

RadioButton est un ensemble de bouton radio (un seul sélectionné à la fois) pour une même variable. La variable retour rendra la valeur proposée par value du bouton sélectionné.

import Tkinter
racine=Tkinter.Tk()
retour=Tkinter.IntVar() # cree une variable entiere pour recevoir la valeur retour
retour.set(2) # le bouton [Bof] mis par defaut (value=2)
bouton1=Tkinter.Radiobutton(racine, text="Oui", variable=retour, value=1, bd=2)
bouton2=Tkinter.Radiobutton(racine, text="Bof", variable=retour, value=2, bd=3)
bouton3=Tkinter.Radiobutton(racine, text="Non", variable=retour, value=3, bd=3)
bouton1.grid(row=0, column=0)
bouton2.grid(row=0, column=1)
bouton3.grid(row=0, column=2)
racine.mainloop()

print retour.get() # retourne 1, 2 ou 3 selon le bouton choisi, ou 0 si pas de choix

Attention: sans retour.set(), si une valeur de retour est mise à 0, le bouton apparaîtra coché.

retour=Tkinter.StringVar() permet d'initialiser une variable pour une valeur de retour sous forme de chaîne. value doit alors recevoir une "chaîne".

3. L'espace graphique Canvas

Canvas crée une surface sur laquelle on peut placer des éléments graphiques (l'exemple suivant n'est pas fonctionnel par manque de commandes):

import Tkinter
racine=Tkinter.Tk()
fond=Tkinter.Canvas(racine, width=300, height=200, background='darkgray')
fond.pack()
# ... votre script
racine.mainloop()

Pour la plupart des éléments graphiques présentés ci-dessous, fill définit la couleur (le texte pour creat_text), width l'épaisseur, outline la couleur du bord, anchor l'alignement.

3.1 Texte graphique

Pour positionner un texte au pixel près sur un canevas (attention: le positionnement par défaut est le centre du texte, comme le montrent les deux lignes)

import Tkinter
racine=Tkinter.Tk()
fond=Tkinter.Canvas(racine, width=150, height=120, background='darkgray')
ligne1=fond.create_line(75, 0, 75, 120)
ligne2=fond.create_line(0, 60, 150, 60)
txt=fond.create_text(75, 60, text="Spam?", font="Arial 16 italic", fill="green")

fond.pack()
racine.mainloop()

Rappel: la couleur du texte est définie ici par fill!

3.2 Lignes et points Rév 2014.05

Avec fond représentant l'ouverture d'un canevas:

import Tkinter
racine=Tkinter.Tk()
fond=Tkinter.Canvas(racine, width=350, height=200, background='darkgray')
ligne=fond.create_line(40,190, 250,110, 270,170, 180,120, width=5)
fond.pack()
racine.mainloop()

Les arguments commencent par une série de paires qui sont des coordonnées de points (deux paires minimum pour un segment de droite). Les paramètres peuvent être ajoutés:

smooth=True pour une courbe au lieu d'une ligne brisée ("spline")
splinesteps=12 nombre de brisures pour un lissage imparfait de la courbe si smooth=True

arrow=Tkinter.BOTH place une flèche aux bouts de la ligne (Tkinter.FIRST pour le départ, Tkinter.LAST pour la fin)
arrowshape=(8,10,3) permet de modifier la longueur de la flèche (sur la ligne), la longueur et la largeur des ailes. arrowshape=(20,10,5) pour un losange

Si la largeur de la ligne est suffisante:

capstyle=Tkinter.ROUND fin de ligne arrondie
capstyle=Tkinter.BUTT fin de ligne coupée
capstyle=Tkinter.PROJECTING fin de ligne coupée, une demi-largeur au delà des coordonnées du point

joinstyle=Tkinter.ROUND angle de deux segments arrondi
joinstyle=Tkinter.MITER angle de deux segments pointu
joinstyle=Tkinter.BEVEL angle de deux segments coupé (orthogonale de la bissectrice)

Dessiner un point

Pour afficher un point x,y, il faut afficher une ligne qui va de x,y à x+1,y ou x,y+1 (le dernier point d'une ligne n'est pas affiché):

import Tkinter
racine=Tkinter.Tk()
fond=Tkinter.Canvas(racine, width=350, height=200, background='darkgray')
ligne=fond.create_line(100,100, 101,100)
fond.pack()
racine.mainloop()

3.3 Formes géométriques Rév 2014.05

Pour fond représentant l'ouverture d'un canevas (les couleurs ont été exécutées pour l'exemple):

import Tkinter
racine=Tkinter.Tk()
fond=Tkinter.Canvas(racine, width=350, height=200, background='darkgray')
rect=fond.create_rectangle(50,40,300,90, fill='white', outline='red', width=10)
ellipse=fond.create_oval(30,120,150,180, fill='green', outline='blue', width=5)
quartier=fond.create_arc(160,130,230,200, start=30,extent=120, fill='yellow', outline='purple', width=5, style=Tkinter.PIESLICE)
arc=fond.create_arc(250,130,320,200 ,start=30,extent=120, fill='black', outline='magenta', width=5, style=Tkinter.CHORD)
fond.pack()
racine.mainloop()

Pour les formes géométriques, les deux premiers entiers représentent les coordonnées du point en haut à gauche du rectangle, les deux suivants celles du point en bas à droite. Pour create_oval et create_arc, il s'agit des coordonnées du rectangle circonscrit.

Pour create_arc, l'angle de départ et l'extension sont donnés en degrés (progression trigono­mé­trique, anti-horaire). Tkinter.PIESLICE dessine un quartier de tarte, Tkinter.CHORD un arc et sa corde.

Polygones

Pour dessiner un polygone, éventuellement arrondi, il faut en déterminer les différentes coordonnées de points (sans se préoccuper de répéter les coordonnées du premier):

import Tkinter
racine=Tkinter.Tk()
fond=Tkinter.Canvas(racine, width=150, height=150, background='darkgray')
polygone=fond.create_polygon(35,105, 120,85, 95,25, 80,75, 25,60, 65,30, fill="cyan", width=5, outline='black')
fond.pack()
racine.mainloop()

smooth=True et splinesteps=n sont disponibles pour les polygones.

3.4 Afficher un fichier-image

Tkinter ne reconnaît que les formats GIF et certains PNM (voir plus bas). Voici la façon d'afficher une image (le fichier exemple.gif doit exister dans le répertoire du script):

import Tkinter
racine=Tkinter.Tk()

photo=Tkinter.PhotoImage(file="exemple.gif")  # ouverture du fichier existant image.gif
largeur=photo.width(); hauteur=photo.height() # determination des dimensions
racine.geometry(str(largeur+2)+'x'+str(hauteur+2))
racine.title(str(largeur)+'x'+str(hauteur))

fond=Tkinter.Canvas(racine, bg='gray')
fond.pack()
img=fond.create_image(largeur//2+1,hauteur//2+1,image=photo) # image a centrer
racine.mainloop()

Les dimensions de l'image servent à définir la surface utile pour le canevas.

Par défaut, l'image est centrée sur le point de coordonnées précisé (avant-dernière ligne). Il est possible de changer cela en précisant le point supérieur gauche et ajoutant l'alignement anchor=Tkinter.NW:

img=fond.create_image(0, 0, image=photo, anchor=Tkinter.NW)

Formats PNM: PGM et PPM Ajout 2014.05

Seul les PNM au format brut (binaire) en nuances de gris (PNM ou PGM) ou couleurs (PNM ou PPM), à savoir ceux dont l'entête commence par P5 ou P6, peuvent être affichés par Tkinter. Pour des renseignements sur ces formats non compressés et faciles à générer: P5 et P6.

Il est par ailleurs possible de coder un fichier PNM dans un script:

import Tkinter

p5="P5 8 8 255 "+((chr(255)*2+chr(0)*2)*4+(chr(0)*2+chr(255)*2)*4)*2
# (2px blancs suivis de 2px noirs)x4 + (2px noirs suivis de2px blancs)x4,
# le tout x2, fait un damier de 4x4 carrés de 2x2px

racine=Tkinter.Tk()

fond=Tkinter.Canvas(racine)
damier=Tkinter.PhotoImage(data=p5)
image1=fond.create_image(120, 120, image=damier)
fond.pack()

racine.mainloop()

Ce n'est pas trop pratique, le format suivant convient probablement mieux.

3.5 Afficher une image bitmap Ajout 2014.05

Tkinter permet d'utiliser une image bitmap bicolore xbm. Chaque pixel correspondant à un bit mis à 1 donne la couleur définie par foreground et chaque pixel correspondant à un bit mis à 0 laisse la couleur de fond du canevas inchangée, ou celle précisée par background de BitmapImage().

import Tkinter

im_bitmap="""
# define im_width 24
# define im_height 16
# static char im_data[] = {
0x0f,0x0,0xcc,0x0f,0x0,0xcc,0x0f,0x0,0x33,0x0f,0x0,0x33,0xf0,0x0,0xcc,0xf0,
0x0,0xcc,0xf0,0x0,0x33,0xf0,0x0,0x33,0x0,0xff,0x0,0x0,0xff,0x0,0x0,0xc3,
0x0,0x0,0xc3,0x0,0x0,0xc3,0x0,0x0,0xc3,0x0,0x0,0xff,0x0,0x0,0xff,0x0
};
"""

racine=Tkinter.Tk()

fond=Tkinter.Canvas(racine, background='gray')
damier=Tkinter.BitmapImage(data=im_bitmap, foreground="red", background="blue")
print damier.width(),damier.height()
image0=fond.create_image(20, 20, image=damier)
fond.pack()

racine.mainloop()

La définition de l'image provient de la syntaxe du langage C, qu'il convient plus ou moins de respecter. Après expérimentation, les trois premières lignes doivent commencer par le # et respectivement comporter _width et une largeur en pixels, _height et une hauteur en pixels, et char suivi d'un nom de variable-liste dont le choix semble arbitraire. Chaque octet (ici sous forme hexadécimale) contient huit pixels, la séquence 10101010 étant codée 0xaa, selon la conversion par quartet:

0000 → 0    0010 → 2    0100 → 4    0110 → 6    1000 → 8    1010 → a    1100 → c    1110 → e
0001 → 1    0011 → 3    0101 → 5    0111 → 7    1001 → 9    1011 → b    1101 → d    1111 → f

Il est possible de charger un fichier, au même format, avec damier=Tkinter.BitmapImage(file="image.xbm")

Comme pour les fichiers-images, damier.width() et damier.width() retourne la largeur et la hauteur de l'image bitmap, pour la variable damier issu de Tkinter.BitmapImage().

Si background a été précisé, il est possible de définir un masque, au même format, qui décide des pixels affichés:

masque="""
# define mask_width 24
# define mask_height 16
# static char mask[] = {
0xaa,0xaa,0xaa,0x55,0x55,0x55,0xaa,0xaa,0xaa,0x55,0x55,0x55,0xaa,0xaa,0xaa,0x55,
0x55,0x55,0xaa,0xaa,0xaa,0x55,0x55,0x55,0xaa,0xaa,0xaa,0x55,0x55,0x55,0xaa,0xaa,
0xaa,0x55,0x55,0x55,0xaa,0xaa,0xaa,0x55,0x55,0x55,0xaa,0xaa,0xaa,0x55,0x55,0x55
};
"""

et l'appel doit être complété:

damier=Tkinter.BitmapImage(data=im_bitmap, foreground="black", background="white", maskdata=masque)

Bizarrement, les expérimentations montrent que les bits de masque sont inversés dans les octets: le masque 00001010 doit être codé 01010000, soit 0x50 en hexadécimal. L'ordre des octets est maintenu.

3.6 Reconfigurer un élément

L'instance récupérée lors de la création permet de manipuler les objets créés. Pour une ellipse créée avec la variable ellipse0:

fond.itemconfigure(ellipse0,fill="green") colore l'objet ellipse0 en vert
fond.delete(rectangle1) détruit l'élément rectangle1

L'exemple suivant permet de changer la couleur d'un rectangle par un clic sur un bouton):

#! /usr/bin/python
import Tkinter
racine=Tkinter.Tk()

fond=Tkinter.Canvas(racine, width=300, height=200, background='darkgray')
fond.pack()
rectangle=fond.create_rectangle(50,50, 250,150, fill='gray')

def rouge():
  fond.itemconfig(rectangle, fill='red')
def vert():
  fond.itemconfig(rectangle, fill='green')
def bleu():
  fond.itemconfig(rectangle, fill='blue')

bouton1=Tkinter.Button(racine, text="Rouge!", command=rouge)
bouton2=Tkinter.Button(racine, text="Vert!", command=vert)
bouton3=Tkinter.Button(racine, text="Bleu!", command=bleu)
bouton1.pack(side=Tkinter.LEFT)
bouton3.pack(side=Tkinter.RIGHT)
bouton2.pack()

racine.mainloop()

Il est à noter que le nom de la fonction-cible de Tkinter.Button s'écrit sans guillement ni parenthèse.

side=Tkinter.LEFT et Tkinter.RIGHT permettent d'aligner les boutons à gauche et à droite.

4. Fenêtres, cadres et panneaux

4.1 TopLevel

TopLevel permet l'ouverture d'une nouvelle fenêtre. Afin de ne pas surcharger l'exemple, la nouvelle fenêtre n'affiche rien de plus que la première.

import Tkinter
racine=Tkinter.Tk()
racine.title("Principale")
fenetre=Tkinter.Toplevel()
fenetre.title("Seconde")
fenetre.grid()
racine.mainloop()

Deux fenêtres vont s'ouvrir: la principale, nommée pour l'occasion Principale, et la seconde, appelée Seconde. On subordonne le plus souvent la création d'une seconde fenêtre à un événement de la première, par exemple associée au clic d'un bouton. Fermer la principale ferme la seconde, l'inverse n'est pas vrai.

4.2 Frame et LabelFrame

Frame est un cadre, permettant de regrouper géographiquement les widgets dans une fenêtre.

import Tkinter
racine=Tkinter.Tk()
Cadre=Tkinter.Frame(racine)
bouton1=Tkinter.Button(Cadre,text="Bouton 1")
bouton2=Tkinter.Button(Cadre,text="Bouton 2")
bouton3=Tkinter.Button(Cadre,text="Bouton 3")
bouton1.pack(side=Tkinter.LEFT)
bouton2.pack(side=Tkinter.TOP)
bouton3.pack()
Cadre.pack()
racine.mainloop()

Il est possible de donner un bord et un nom à un cadre avec LabelFrame:
Cadre=Tkinter.LabelFrame(racine,text="Titre de cadre")

4.3 PanedWindow

PanedWindow permet de diviser une fenêtre en plusieurs panneaux adaptables.

import Tkinter
racine=Tkinter.Tk()
racine.geometry("400x300")
division=Tkinter.PanedWindow(orient=Tkinter.VERTICAL)
division.pack(expand="yes",fill="both")
panneau1=Tkinter.Label(division,text="Panneau Un")
division.add(panneau1)
panneau2=Tkinter.Label(division,text="Panneau Deux")
division.add(panneau2)
panneau3=Tkinter.Label(division,text="Panneau Trois")
division.add(panneau3)
racine.mainloop()

On adapte cette fonction dans l'autre direction avec les paramètres suivants: orient=Tkinter.HORIZONTAL.

Il est possible de créer des subdivisions dans un des panneaux. Dans l'exemple suivant, c'est le panneau bas qui devient l'objet à diviser par PanedWindows: c'est donc à lui que les sous-panneaux gauche et droite doivent se référer.

import Tkinter
racine=Tkinter.Tk()
racine.geometry("400x300")
division=Tkinter.PanedWindow(orient=Tkinter.VERTICAL)
division.pack(expand="yes",fill="both")
haut=Tkinter.Label(division,text="Panneau du haut")
division.add(haut)
milieu=Tkinter.Label(division,text="Panneau du milieu")
division.add(milieu)
bas=Tkinter.PanedWindow(orient=Tkinter.HORIZONTAL) # nouvelle division
bas.pack(expand="yes",fill="both")
gauche=Tkinter.Label(bas,text="Panneau bas-gauche")
bas.add(gauche)
droit=Tkinter.Label(bas,text="Panneau bas-droit")
bas.add(droit)
division.add(bas) # on acheve la declaration du panneau bas
racine.mainloop()

5.1 Listbox

2014.05.27 - Cette section a été complétée pour gérer selectmode=MULTIPLE

Le script suivant permet le transfert dans la zone texte d'un mot dans une liste, par un double clic gauche.

#! /usr/bin/python

import Tkinter

racine=Tkinter.Tk()

liste=Tkinter.Listbox(racine,width=10)
liste.pack()

texte=Tkinter.Text(racine,width=10)
texte.pack()

for element in ["Monthy","Python","Flying","Circus"]:
  liste.insert(Tkinter.END, element)

def clic(inutile):
  texte.insert(Tkinter.INSERT,liste.get(liste.curselection())+" ")

liste.bind('<Double-1>', clic)
racine.mainloop()

La boucle for remplit la liste des éléments dans la Listbox.
inutile est une variable nécessaire mais qu'on n'utilise pas.
INSERT permet d'ajouter l'élément cliqué à l'endroit du curseur (END pour la fin du texte, CURRENT pour le début)

Il est possible de remplacer le double-clic par une confirmation par bouton:

#! /usr/bin/python

import Tkinter
racine=Tkinter.Tk()

liste=Tkinter.Listbox(racine,width=10,selectmode=Tkinter.MULTIPLE)
liste.pack()

bouton=Tkinter.Button(racine,text='Confirmer')
bouton.pack()

texte=Tkinter.Text(racine,width=10)
texte.pack()

for element in ["Monthy", "Python", "Flying", "Circus"]:
  liste.insert(Tkinter.END, element)

def clic(inutile):
  for i in liste.curselection():
    texte.insert(Tkinter.INSERT,liste.get(i)+" ")

bouton.bind('<Button-1>', clic)
racine.mainloop()

De plus, Listbox accepte selectmode=Tkinter.MULTIPLE pour un mode de sélection multiple en cliquant successivement sur plusieurs items, et EXTENDED qui permet Ctrl-Clic pour une succession d'items et Maj-Clic pour une suite d'items consécutifs. Il a fallu modifier la fonction clic pour qu'elle accepte une réponse multiple, sous forme de tuple contenant les index des items choisis.

Pour être complet, il faudrait également parler de selectmode=Tkinter.BROWSE censé déplacer un item en le tirant (drag'n drop), mais cela ne semble pas fonctionner.

Le mode par défault est selectmode=Tkinter.SINGLE, qui fonctionne mal avec "<Button-1>" (simple clic gauche): l'élément cliqué arrive avec un coup de retard.

5.2 Scrollbar

Scrollbar permet de faire défiler dans une surface limitée quelques widgets, comme Text, Entry, Listbox, et Canvas comme expliqué plus bas.

#! /usr/bin/python

import Tkinter
racine = Tkinter.Tk()

def afficher(dummy):
  print liste.curselection()

ascenseur= Tkinter.Scrollbar(racine, orient=Tkinter.VERTICAL)
ascenseur.pack(side=Tkinter.RIGHT, fill=Tkinter.Y)

liste= Tkinter.Listbox(racine, yscrollcommand=ascenseur.set)
for i in range(0,128):
  liste.insert(Tkinter.END, str(i))

liste.pack(fill=Tkinter.Y)
ascenseur.config(command=liste.yview)

liste.bind('<Double-1>', afficher)

racine.mainloop()

orient=Tkinter.VERTICAL est l'orientation par défaut
fill=Tkinter.Y met de l'espace entre les deux flèches de l'ascenseur horizontal
side=Tkinter.LEFT aurait placé l'ascenseur à gauche

Il était possible de garder le défilement vertical de la liste de nombres avec un ascenseur horizontal, en changeant ses deux lignes de définitions:

ascenseur= Tkinter.Scrollbar(racine, orient=Tkinter.HORIZONTAL)
ascenseur.pack(side=Tkinter.TOP, fill=Tkinter.X)

Par contre, la commande liste.yview doit rester la même, puisque le défilement est vertical

Ascenseur avec Canvas

Merci à http://effbot.org/tkinterbook/

Pour le widget Canvas, c'est un peu plus compliqué. Premièrement, il semble qu'il faille l'inclure dans un cadre Frame(). Deuxièmement, le paramètre scrollregion=() doit préciser les dimensions de la plage entière concernée par le défilement.

import Tkinter
fenetre=Tkinter.Tk()

cadre=Tkinter.Frame(fenetre,width=300,height=300)
cadre.pack()
canvas=Tkinter.Canvas(cadre,bg='#FFFFFF',width=250,height=200,scrollregion=(0,0,250,250))

ascenseur=Tkinter.Scrollbar(cadre)
ascenseur.pack(side=Tkinter.RIGHT,fill=Tkinter.Y)
ascenseur.config(command=canvas.yview)

canvas.config(width=250,height=200)
canvas.config(yscrollcommand=ascenseur.set)
canvas.pack(side=Tkinter.LEFT,expand=True)

txt1=canvas.create_text(12, 12, text="T'es fou\nTire pas\nC'est pas des corbeaux\nC'est mes souliers\nJe dors parfois dans les arbres", width=280, anchor=Tkinter.NW)

txt2=canvas.create_text(12, 200, text="'Moi dans l'arbre'\nPaul Vicensini", width=280, anchor=Tkinter.NW)

fenetre.mainloop()

5.3 Menu

Voici un exemple commenté d'un système de menu fonctionnel comportant des cascades (sous-menus). Pour la fonction Menu, deux méthodes sont nécessaires: add_cascade pour ajouter un menu ou un sous-menu, et add_command pour décider de la commande associée au clic. Les actions sont ici limitées à l'affichage d'un texte.

import Tkinter
racine=Tkinter.Tk()

texte=Tkinter.Text(racine) # prevoit une place pour l'affichage des textes
texte.pack()

def ecran(var): # fonction servant a l'affichage des textes:
  texte.insert(Tkinter.END,var)

sysdemenu = Tkinter.Menu(racine) # Creation du systeme de menu (variable explicite sysdemenu):

menu1 = Tkinter.Menu(sysdemenu) # Creation du premier menu:
sysdemenu.add_cascade(label="Menu 1", menu=menu1)

# addition des deux items pour le premier menu et leur commande associee
menu1.add_command(label="Cre9dit", command=lambda: ecran('Credit: www.jchr.be\n'))
menu1.add_command(label="Quitter", command=racine.quit)

menu2 = Tkinter.Menu(sysdemenu) # Creation du second menu
sysdemenu.add_cascade(label="Menu 2", menu=menu2)

# addition du premier item pour le second menu et leur sous-items associes
item1 = Tkinter.Menu(menu2)
menu2.add_cascade(label="Item 1", menu=item1)

# addition des sous-items du premier item du second menu et leur commande associee
item1.add_command(label="Action 1", command=lambda: ecran('Item 1 / Action 1\n'))
item1.add_command(label="Action 2", command=lambda: ecran('Item 1 / Action 2\n'))

item2 = Tkinter.Menu(menu2) # addition du second item pour le second menu et leur sous-items associes
menu2.add_cascade(label="Item 2", menu=item2)

# addition des sous-items du second item du second menu et leur commande associee
item2.add_command(label="Action 1", command=lambda: ecran('Item 2 / Action 1\n'))
item2.add_command(label="Action 2", command=lambda: ecran('Item 2 / Action 2\n'))
item2.add_command(label="Action 3", command=lambda: ecran('Item 2 / Action 3\n'))
racine.config(menu=sysdemenu)
racine.mainloop()

Chaque menu commence par une ligne discontinue. Un clic transfère le menu dans une fenêtre indépendante. On peut empêcher cela en ajoutant le paramètre tearoff=0 dans la fonction Menu.

6. Styles

6.1 grid Ajout 2014.05

grid permet de placer des widgets dans une grille, selon les coordonnées rangée (row) / colonne (column). Ne jamais mélanger pack() et grid dans le même frame.

import Tkinter

def afficher(): # interroge et sort de la valeur retour
  print retour.get()

racine=Tkinter.Tk()
cadre0=Tkinter.Frame(racine)

# titre pour chaque ligne
Tkinter.Label(cadre0, text=" 1er").grid(row=0, column=0)
Tkinter.Label(cadre0, text=" 2nd").grid(row=0, column=1)
Tkinter.Label(cadre0, text=" 3e").grid(row=0, column=2)

retour=Tkinter.IntVar()
b1=Tkinter.Radiobutton(cadre0, text="Oui", variable=retour, value=1)
b2=Tkinter.Radiobutton(cadre0, text="Bof", variable=retour, value=3)
b3=Tkinter.Radiobutton(cadre0, text="Non", variable=retour, value=2)

b1.grid(row=1, column=0)
b2.grid(row=2, column=1)
b3.grid(row=1, column=2)

cadre0.pack(side=Tkinter.TOP)

bouton=Tkinter.Button(racine, text="Cliquer", command=afficher)
bouton.pack(side=Tkinter.BOTTOM)

racine.mainloop()

6.2 Alignements Rév 2014.08

Le préfixe Tkinter des constantes officielles doit être remplacé par son alias s'il a été importé de la façon import Tkinter as alias.

Les paramètres side="" pour pack() et les ascenseurs, ou justify="" pour les textes, acceptent "top", "right", "bottom" et "left". Les constantes officielles sont Tkinter.TOP, Tkinter.RIGHT, Tkinter.BOTTOM et Tkinter.LEFT.

compound accepte en outre "center" et "none". Pour les boutons acceptant une icone, none fait disparaître non pas l'icone mais le texte. Tkinter.CENTER et Tkinter.NONE sont les constantes officielles.

Pour anchor (positionnement des images):
Le paramètres anchor se base sur les points cardinaux n, e, s et w (ouest): "n", "ne", "e", "se", "s", "sw", "w", "nw" et "center". Les constantes officielles contenant ces chaînes sont Tkinter.N, Tkinter.NE, Tkinter.E, Tkinter.SE, Tkinter.S, Tkinter.SW, Tkinter.W, Tkinter.NW, Tkinter.CENTER.

6.3 Reliefs Rév 2014.08

Le préfixe Tkinter des constantes officielles doit être remplacé par son alias s'il a été importé de la façon import Tkinter as alias.

relief="" peut prendre les valeurs "raised" (élevé), "sunken" (enfoncé), "flat" (plat, par défaut), "groove" (rainure) ou "ridge" (crête). Les constantes officielles sont Tkinter.RAISED, Tkinter.SUNKEN, Tkinter.FLAT, Tkinter.GROOVE ou Tkinter.RIDGE.

borderwidth="" ou bd="" permet de préciser la grosseur des traits. L'image ci-dessous a été réalisée avec bd="3"

relief=raised, sunken, flat, groove, ou ridge

6.4 Fontes Rév 2014.08

Valable pour Label, Text et create_text, il y a plusieurs manières d'imposer une fonte, une hauteur et une décoration:

font =("Courier", "16", "bold italic")
font="Courier 30 bold" font=("-*-Helvetica-medium-r-*-*-*-200-*-*-*-*-*-*")

import Tkinter
racine=Tkinter.Tk()
lbl0=Tkinter.Label(racine, text="Texte gras et italique",font="Courier 100 bold italic")
lbl0.pack()
racine.mainloop()

serif, sans, monospace ou toute fonte installée: Times, Helvetica, courier, arial...
une hauteur de caractère en points d'imprimerie (72e de pouce) bold italic underline, overstrike pour la graisse, le style et les décorations

6.5 Couleurs

On utilise la forme "#RRGGBB" où les lettres représentent le rouge, le vert et le bleu en chiffres hexadécimaux (de 0 à 9 puis de a à f). Cette chaîne est à fournir aux paramètres foreground="", background="", fill="" et outline=""

Il existe des couleurs toutes faites parmi lesquelles:

black, gray1... dark-gray, dimgray, gray, light-gray, ...gray99, white
red (~2/ ~3/ ~4), pink, deep pink
yellow,
green (dark ~/lawn ~/lime ~/forest ~/yellow ~), olive drab
blue (medium ~/midnight ~/steel ~), navy, sky blue (deep ~/light ~), cyan
magenta, violet, purple
orange, gold, lightblue, darkblue

Voir également la boîte de choix de couleur.

7. Modules associés

Les quatre librairies qui suivent permettent d'ouvrir des boîtes toutes faites, qui permettent d'avertir, de demander une confirmation, de préciser une valeur, de sélectionner un fichier ou même de choisir une couleur.

7.1 Boîtes à message Rév 2014.08

Si le paquet Debian python-tk est installé: import tkMessageBox importe les fonctions de boîte à messages. Le bouton par défaut (que l'on peut confirmer par [Enter]) est toujours celui de gauche: [Ok], [Yes] ou [Retry], il faut sinon le préciser avec default="no" ou default="cancel".

Retournent ok, bouton nécessairement par défaut:

tkMessageBox.showinfo()
tkMessageBox.showwarning()
tkMessageBox.showerror()

Retourne yes ou no

tkMessageBox.askquestion()   # default="yes" - sinon, préciser default="no"

Retournent True ou False, ou encore None pour askyesnocancel():

tkMessageBox.askokcancel()    # default="ok" - sinon, préciser default="cancel"
tkMessageBox.askyesno()       # default="yes" - sinon, préciser default="no"
tkMessageBox.askyesnocancel() # default="yes" - sinon, préciser default="no" ou "cancel"
tkMessageBox.askretrycancel() # default="retry" - sinon, préciser default="cancel"

Paramètres

title="" donne un titre à la boîte de message ou de choix.

message="" définit le message en gras, à l'intérieur de la boîte.

detail="" permet un message secondaire, dans une fonte de plus petite taille.

icon="" permet de forcer le type d'icone "error", "info", "question" ou "warning", quelle que soit le type de réponse possible. L'exemple ci-dessous permet un choix Oui/Non mais avec l'icone du i dans un phylactère.

import tkMessageBox
tkMessageBox.askyesno(icon="info")

type= permet de forcer d'autres choix dans une boîte particulière avec les valeurs "ok", "yesno", "okcancel", "retrycancel", or "yesnocancel". L'exemple suivant permet d'afficher la boîte d'erreur (la x blanche sur le disque rouge de showerror), mais avec un choix entre [Oui] et [Non].

import tkMessageBox
tkMessageBox.showerror(type="yesno")

Un dernier type est abortretryignore, qui renvoie les choix "abort", "retry" ou "ignore", inédit parmi les boîtes "toutes faites".

En python3 Ajout 2014.05

Pour python3, le paquet Debian à installer est python3-tk et messagebox est un sous-module de tkinter. Par exemple,

import tkinter.messagebox
texte0=tkinter.messagebox.askquestion(title="Titre", message="Message")

7.2 Boîtes de saisie Rév 2014.08

Si le paquet Debian python-tk est chargé, import tkSimpleDialog charge un module permettant l'affichage de boîtes de saisie de données. racine représente le widget parent, issu de racine=Tkinter.Tk().

tkSimpleDialog.askstring("Titre", "Invitation", parent=racine)
tkSimpleDialog.askinteger("Titre", "Invitation", parent=racine)
tkSimpleDialog.askfloat("Titre", "Invitation", parent=racine)

On peut ajouter quelques options valables pour entiers, décimaux ou chaînes, où "ac" est inférieur à "d" (les non-entiers s'écrivent avec le point décimal: 1.6 et non 1,6
initialvalue= valeur de départ
minvalue= valeur minimale
maxvalue= valeur maximale

En python3 Rév 2014.08

Pour python3, le paquet Debian s'appelle python3-tk et simpledialog est un sous-module de tkinter. Par exemple,

import tkinter.simpledialog
racine=tkinter.Tk()
chaine=tkinter.simpledialog.askstring("Exprimez-vous!", "Veuillez dire ce que vous pensez", parent=racine)
racine.mainloop()

7.3 Sélectionneur de fichier Rév 2014.08

Si le paquet Debian python-tk est chargé: import tkFileDialog

repertoire=tkFileDialog.askdirectory()  # pour choisir un répertoire
fichier1=tkFileDialog.askopenfilename() # pour sélectionner le nom d'un fichier à ouvrir
fichier2=tkFileDialog.asksaveasfilename() # pour sélectionner le nom d'un fichier à sauvegarder

Les variables fichier1 et fichier2 contiennent le nom du fichier à ouvrir ou à sauvegarder. Pour le traitement même, voir ici. Mais deux autres instructions permettebt de combiner choix de fichier et traitement (sauvegarde ou chargement).

asksaveasfile(mode='w') permet de combiner la navigation dans une arborescence, la sélection du nom et la sauvegarde d'un fichier (han est ici le descripteur du fichier, pas son nom):

import tkFileDialog
han=tkFileDialog.asksaveasfile(initialfile="essai.txt",mode='w',title="Sauvegarde d'un fichier texte")
han.write("Texte très court")
han.close() 

askopenfile(mode='r') permet de combiner la navigation dans une arborescence, la sélection du nom et le chargement d'un fichier (han est ici le descripteur du fichier, pas son nom):

import tkFileDialog
han=tkFileDialog.askopenfile(initialfile="essai.txt",mode='r',title="Chargement d'un fichier texte")
print han.read()
han.close()

Options:

initialdir="" indique un répertoire de départ, pas de message d'erreur si le répertoire est absent

initialfile="" nom de fichier préétabli. Pour asksaveasfilename(), demande de confirmation si un fichier existant est sur le point d'être écrasé

multiple="true" ou multiple=True - pour askopenfilename() seulement - permet le choix de plusieurs fichiers (avec [shft-clic] et [ctrl-clic], retournés sous forme de liste.

filetypes=[] permet de définir des associations ('type','ext') permettant de filtrer les fichiers selon leur extension. Les tuples ('','') sont collectés dans une liste:

associations=[("Fichiers 'texte'", '.txt'), ("Fichiers 'html'", '.htm'), ("Tous les fichiers", '.*')]
fichier1=tkFileDialog.askopenfilename(filetypes=associations)

Sauvegarder

asksaveasfile(mode='w') permet de combiner la navigation dans une arborescence, la sélection du nom et la sauvegarde d'un fichier:

import tkFileDialog
han=tkFileDialog.asksaveasfile(initialfile="essai.txt",mode='w',title="Sauvegarde d'un fichier texte")
han.write("Texte très court")
han.close() 

En python3 Rév 2014.08

Le paquet Debian à installer s'appelle python3-tk. filedialog est un sous-module de tkinter:

import tkinter.filedialog
fichier1=tkinter.filedialog.askopenfilename()
fichier2=tkinter.filedialog.asksaveasfilename(defaultextension="png")
fichier2=tkinter.filedialog.askdirectory()

7.4 Choisir une couleur Rév 2014.05

Si le paquet Debian python-tk est installé sur votre système, il est possible d'importer le module: import tkColorChooser()

((rouge,vert,bleu),couleur)=tkColorChooser.askcolor() fait apparaître un sélectionneur de couleur. Le tuple (rouge,vert,bleu) retourne les couleurs fondamentales (de 0 à 255), la variable couleur contient la couleur au format #RRVVBB.

Il est possible de recueillir la couleur en un seul (tuple):

#! /usr/bin/python

import tkColorChooser
tup=tkColorChooser.askcolor(initialcolor=(150,200,250),title="Choisir une couleur...")
print tup[0][0] # est la quantite de rouge (non entier)
print tup[0][1] # est la quantite de vert (non entier)
print tup[0][2] # est la quantite de bleu (non entier)
print tup[1]    # est la couleur sous la forme #RRVVBB (chaine)

Attention: les couleurs rouge, vert et bleu du tuple ((rouge,vert,bleu),couleur) sont des nombres réels! Pour la chaine #RRVVBB exprimée en hexadécimal retournée par la variable couleur, il est simple de récupérer les couleurs de base de cette manière:

rouge, vert, bleu = int(couleur[1:3],16), int(couleur[3:5],16), int(couleur[5:],16)

initialcolor=(rouge,vert,bleu) (trois nombres <256) pour une couleur préalablement définie
title="" définit le titre de la fenêtre.

En python Ajout 2014.05

Pour python3, le paquet Debian s'appelle python3-tk et colorchooser est un sous-module de tkinter:

import tkinter.colorchooser
((rouge,vert,bleu),couleur)=tkinter.colorchooser.askcolor()

9. Documentation

9.1 Documentation dans le logiciel python

Dans le mode interactif (obtenu en saisissant python dans une console):

  >>> print dir() liste les modules chargés
  >>> print Tkinter.__file__ renvoie la localisation de Tkinter sur le système
  >>> print dir(Tkinter) liste les instructions du module Tkinter
  >>> print Tkinter.fct.__doc__ documente l'instruction précisée de Tkinter

La commande help informe sur une fonction d'un module importé:

  >>> import Tkinter
  >>> help(Tkinter.Button)

Pour générer un fichier lisible avec un éditeur de texte, saisir dans une console:

python -c "import Tkinter; help(Tkinter)" > Tk.txt

En python3, le module est rebaptisé tkinter. Il faudra alors choisir un de ces chargements de module:

python3 -c "import tkinter; help(Tkinter)" > tk.txt

9.2 Documentation sur votre système GNU/Linux

Si python est installé, saisir man python dans une console renseigne sur les différentes manières de lancer python.

Le script /usr/bin/pydoc permet la consultation d'information de fonctions, modules, mots-clés:
pydoc -g lance une interface graphique pour une navigation dans le système d'aide

9.3 Documentation sur Internet

9.4 Documentation sur papier