FAQ Tkinter

FAQ Tkinter #

Widgets de base #

Les petits programmes qui suivent sont tous fonctionnels. En règle générale, les variables qui sont accédées à plusieurs endroits du programme sont stockées dans un dictionnaire, de manière à n’avoir finalement qu’une seule variable globale.

Bouton #

import tkinter as tk

def bouton_cb():
    print("Vous avez cliqué")

def gui(root):
    frame = tk.Frame(root)
    frame.pack(expand=1, fill='both')
    open_button = tk.Button(frame, text="Bouton", command=bouton_cb)
    open_button.pack(padx=8, pady=8)

root = tk.Tk()
gui(root)
root.mainloop()

Entry #

import tkinter as tk

g_entry = None # Variable globale

def entree_cb(ev):
    print("Vous avez écrit : " + g_entry.get())

def gui(root):
    global g_entry
    frame = tk.Frame(root)
    frame.pack(expand=1, fill='both')
    g_entry = tk.Entry(frame)
    g_entry.pack(padx=8, pady=8)
    # Pour appeler une callback si on appuie sur Entrée :
    g_entry.bind('<Return>', entree_cb)

root = tk.Tk()
gui(root)
root.mainloop()

OptionMenu #


import tkinter as tk

v_menu = None # Variable globale

def changement(*ev):
    print("Choix :", v_menu.get())

def gui(root):
    global var
    global v_menu
    liste_choix = ("Option 1", "Option 2", "Option 3")
    frame = tk.Frame(root)
    frame.pack(expand=1, fill=tk.BOTH)

    # On associe une variable au menu
    v_menu = tk.StringVar()
    v_menu.set(liste_choix[0])
    menu = tk.OptionMenu(frame, v_menu, *liste_choix)

    # Appel d'une callback si la variable change
    v_menu.trace('w', changement)

    menu.pack(padx=8, pady=8)
    #menu.place(x=10, y=10, width=300, height=80)

root = tk.Tk()
gui(root)
root.mainloop()

RadioButtons #

import tkinter as tk

def clicked():
    print("Selection : {}".format(v.get()))

root = tk.Tk()
v = tk.IntVar()
v.set(2) # Permet de choisir le radiobutton coché par défaut
a = tk.Radiobutton(root, text="One", variable=v, value=1, command=clicked)
b = tk.Radiobutton(root, text="Two", variable=v, value=2, command=clicked)
a.pack()
b.pack()

root.mainloop()

Dialogues #

Boîte de sélection de fichier #

import tkinter as tk
from tkinter import filedialog
import os.path

def choosefile():
    result = filedialog.askopenfilename(initialdir="C:\\")
    print("RESULT", result, type(result))

def gui(root):
    frame = tk.Frame(root)
    root.title("Exemple ouverture fichier")
    frame.pack(expand=1, fill='both')
    open_button = tk.Button(frame, text="Ouvrir fichier", command=choosefile)
    open_button.pack(padx=8, pady=8)

root = tk.Tk()
gui(root)
root.mainloop()

Événements #

Tester le type d’événement #

La callback suivante est appelée si on appuie sur une touche du clavier ou si on clique avec le bouton gauche de la souris. Comment différencier le type d’événement qui a eu lieu ?

import tkinter as tk

def handler(ev):
    print(ev)
    print(ev.type) # contient un nombre
    if ev.type == tk.EventType.KeyPress: # évite de mettre des valeurs numériques
        print("Clavier")
    elif ex.type == tk.EventType.Button:
        print("Souris"
    else:
        print("Autre événement")

Utiliser la même callback sur plusieurs objets avec partial #

partial permet, à partir d’une fonction prenant des paramètres, d’en créer une nouvelle avec certains paramètres fixés.

#!/usr/bin/env python3
import tkinter as tk
import functools

def connect(texte):
    print("Vous avez  cliqué sur ", texte)

# =====================================================
# Fenêtre principale
# =====================================================
 
class Fenetre(tk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.master.title("Fenêtre principale")
        self.pack(fill='both', expand=1)
        for text in "ABCD":
            temp_bouton = tk.Button(self, width=10, height=1, text=text, 
                                    command=functools.partial(connect, texte="BOUT-{}".format(text)))
            temp_bouton.pack() 
 
# Création de l'application
root = tk.Tk()
# Ajout des éléments graphiques 
gui = Fenetre(root)
# Boucle des événements
root.mainloop()

Widgets complexes #

Intégration d’un graphe Matplotlib dans une application tkinter #

Voici un exemple de code qui intègre un graphe dans une fenêtre tkinter.

import matplotlib
matplotlib.use('TkAgg')

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import random
from matplotlib.figure import Figure

import tkinter as tk

def plot(canvas, figure):
    if figure.axes:
        figure.delaxes(figure.axes[0])
    axes = figure.add_subplot(111)
    x = range(1,10)
    axes.plot(x, [random.random() for _ in x])
    canvas.draw()

def create_ui():
    root = tk.Tk()
    root.wm_title("Embedding in TK")
    root.geometry("500x500")
    frame = tk.Frame(master=root)
    frame.pack(fill=tk.BOTH, expand=1)

    figure = Figure(figsize=(5, 4), dpi=100)
    axes = figure.add_subplot(111)
    canvas = FigureCanvasTkAgg(figure, master=frame)
    canvas.draw()
    canvas.get_tk_widget().place(x=10, y =40, width=400, height=400)

    label = tk.Label(master=frame, text="Le Beau Graphe")
    label.place(x=10, y=10, width=100, height=30)

    # Utilisation d'une fermeture, les valeurs de canvas et figure sont capturées
    button = tk.Button(master=frame, text='update', command=lambda: plot(canvas, figure))
    button.pack(side=tk.BOTTOM)

    return root

root = create_ui()
root.mainloop()

Boîte de dialogue (login/pass) modale avec tkinter #

#!/usr/bin/env python3
import tkinter as tk

# =====================================================
# Fenêtre de connexion
# =====================================================
# Doit hériter de Toplevel pour être une fenêtre séparée
# http://effbot.org/tkinterbook/toplevel.htm

class LoginDialog(tk.Toplevel):
    def __init__(self, parent):
        super().__init__(parent)
        self.title("Fenêtre Modale")
        # ---------------------------------------
        tk.Label(self, text="Login : ").pack()
        self.entry_login = tk.Entry(self)
        self.entry_login.insert(0, "defaultlogin")
        self.entry_login.pack()
        # ---------------------------------------
        tk.Label(self, text="Clé : ").pack()
        self.entry_pass = tk.Entry(self, show='*')
        self.entry_pass.insert(0, "defaultpass")
        self.entry_pass.pack()
        # ---------------------------------------
        tk.Button(self, text="Connexion", command=self.connect).pack()

    def connect(self):
        login = self.entry_login.get().strip()
        key = self.entry_pass.get().strip()
        print("Informations entrées : ", login, key)
        self.destroy()

def connect():
    """ Ouvre une fenêtre modale """
    result = LoginDialog(root)
    result.transient(root)
    result.grab_set()
    root.wait_window(result)

# =====================================================
# Fenêtre principale
# =====================================================

class Fenetre(tk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.master.title("Fenêtre principale")
        self.pack(fill='both', expand=1)
        bouton_new = tk.Button(self, width=10, height=1, text="Connexion", command=connect)
        bouton_new.pack()

# Création de l'application
root = tk.Tk()
# Ajout des éléments graphiques 
gui = Fenetre(root)
# Boucle des événements
root.mainloop()