logo oujood
🔍

Le widget Combobox Tkinter (ttk)

Combobox combine un champ de saisie et un menu déroulant. C'est le widget ttk à privilégier quand on veut proposer une liste d'options sans encombrer l'interface.

OUJOOD.COM

Le widget Combobox fait partie du module ttk (Themed Tk) — il n'existe pas dans le module tkinter classique. Il combine un champ texte et un menu déroulant : l'utilisateur peut soit choisir parmi les options proposées, soit saisir sa propre valeur si on le permet. Son apparence est nettement plus moderne que les widgets classiques.

Combobox de base

📋 Copier le code

import tkinter as tk
from tkinter import ttk   # Combobox est dans ttk

fenetre = tk.Tk()
fenetre.title("Combobox")
fenetre.geometry("320x180")

pays = ["France", "Belgique", "Suisse", "Canada", "Maroc",
        "Tunisie", "Algérie", "Sénégal", "Côte d'Ivoire"]

tk.Label(fenetre, text="Pays :").pack(pady=(20, 4))

combo = ttk.Combobox(fenetre, values=pays, width=22)
combo.set("Choisissez un pays")   # texte affiché par défaut
combo.pack()

def afficher():
    label.config(text=f"Pays sélectionné : {combo.get()}")

tk.Button(fenetre, text="Valider", command=afficher).pack(pady=10)
label = tk.Label(fenetre, text="")
label.pack()

fenetre.mainloop()

combo.get() retourne la valeur affichée dans le champ — que l'utilisateur l'ait saisie ou sélectionnée dans la liste. combo.set() définit la valeur affichée sans la lier à la liste. Pour sélectionner un élément de la liste par indice : combo.current(0) sélectionne le premier.

Mode readonly — liste fermée

Par défaut, l'utilisateur peut saisir n'importe quoi dans le champ. Le mode readonly restreint la saisie aux éléments de la liste :

📋 Copier le code

import tkinter as tk
from tkinter import ttk

fenetre = tk.Tk()
fenetre.geometry("340x200")

niveaux = ["Débutant", "Intermédiaire", "Avancé", "Expert"]
langues  = ["Français", "Anglais", "Arabe", "Espagnol", "Allemand"]

frame = tk.Frame(fenetre)
frame.pack(pady=20)

tk.Label(frame, text="Niveau :").grid(row=0, column=0, sticky="e", padx=10, pady=6)
combo_niv = ttk.Combobox(frame, values=niveaux, state="readonly", width=16)
combo_niv.current(0)   # sélectionne "Débutant" par défaut
combo_niv.grid(row=0, column=1)

tk.Label(frame, text="Langue :").grid(row=1, column=0, sticky="e", padx=10, pady=6)
combo_lang = ttk.Combobox(frame, values=langues, state="readonly", width=16)
combo_lang.current(0)
combo_lang.grid(row=1, column=1)

def valider():
    label.config(text=f"{combo_niv.get()} en {combo_lang.get()}")

tk.Button(fenetre, text="Valider", command=valider).pack()
label = tk.Label(fenetre, text="")
label.pack(pady=6)

fenetre.mainloop()

En mode readonly, le champ est verrouillé mais le menu déroulant reste actif. C'est le comportement attendu pour les formulaires où la valeur doit appartenir à une liste prédéfinie — identique à ce que fait Spinbox en mode readonly, mais avec un menu déroulant plutôt que des flèches.

Réagir à la sélection avec StringVar et bind

Deux façons de détecter un changement : lier le Combobox à une StringVar, ou utiliser l'événement <<ComboboxSelected>> via bind() :

📋 Copier le code

import tkinter as tk
from tkinter import ttk

capitales = {
    "France":   "Paris",
    "Espagne":  "Madrid",
    "Italie":   "Rome",
    "Maroc":    "Rabat",
    "Allemagne":"Berlin",
}

fenetre = tk.Tk()
fenetre.title("Combobox avec événement")
fenetre.geometry("320x160")

tk.Label(fenetre, text="Pays :").pack(pady=(20, 4))

combo = ttk.Combobox(fenetre, values=list(capitales.keys()),
                     state="readonly", width=20)
combo.pack()

label_cap = tk.Label(fenetre, text="Sélectionnez un pays", fg="#555")
label_cap.pack(pady=12)

def sur_selection(event):
    pays = combo.get()
    label_cap.config(text=f"Capitale : {capitales[pays]}")

# <> est déclenché à chaque sélection dans la liste
combo.bind("<>", sur_selection)

fenetre.mainloop()

L'événement virtuel <<ComboboxSelected>> ne se déclenche que quand l'utilisateur choisit un élément dans le menu déroulant — pas quand on appelle combo.set() ou combo.current() par programme. Si vous avez besoin de détecter les deux cas, trace_add sur une StringVar liée avec textvariable est plus fiable.

Pour les listes très longues où la navigation par menu déroulant devient pénible, une Listbox avec champ de filtrage est plus ergonomique.

Par carabde | Mis à jour le 30 avril 2025