Retour à l'accueil

Tkinter ToDo : filtres de recherche export CSV

L'article décrit l'extension de Tkinter ToDo : ajout d'un Combobox pour les priorités, filtrage par boutons radio, recherche en temps réel et export CSV. Inclut le code complet des méthodes avec gestion UTF-8 et tri.

Filtres et export de données dans l'application Tkinter ToDo
Advertisement 728x90

# Application ToDo Tkinter : Filtres, Recherche et Export CSV

L'intégration directe de la sélection de priorité dans le panneau de saisie accélère la création des tâches. Nous remplaçons la boîte de dialogue modale par un ttk.Combobox proposant les options haute, moyenne et basse. L'ajout par Entrée fluidifie le flux de travail.

Dans create_widgets, ajoutez un cadre avec Entry, Combobox et bouton :

from tkinter import ttk

top_frame = tk.Frame(self.root)
top_frame.pack(pady=10, padx=10, fill=tk.X)

self.entry = tk.Entry(top_frame, font=("Arial", 12))
self.entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
self.entry.bind("<Return>", lambda event: self.add_task())

tk.Label(top_frame, text="Priorité :").pack(side=tk.LEFT, padx=(5, 2))
self.priority_var = tk.StringVar(value="medium")
priority_combo = ttk.Combobox(
    top_frame, 
    textvariable=self.priority_var, 
    values=["high", "medium", "low"],
    state="readonly",
    width=8
)
priority_combo.pack(side=tk.LEFT, padx=(0, 5))
priority_combo.set("medium")

self.add_button = tk.Button(top_frame, text="➕ Ajouter", command=self.add_task, bg="light blue")
self.add_button.pack(side=tk.RIGHT)

La méthode add_task est simplifiée : elle récupère les données de self.entry et self.priority_var.get(), enregistre la tâche, vide le champ et rafraîchit la liste.

Google AdInline article slot

Filtrage des Tâches par Statut

Des boutons radio basculent les vues : toutes les tâches, actives uniquement ou terminées. La logique de filtrage s'intègre dans get_sorted_tasks.

Dans __init__, ajoutez self.filter_mode = "all". Dans create_widgets, ajoutez un panneau de filtre avec des Radiobuttons :

filter_frame = tk.Frame(self.root)
filter_frame.pack(pady=5, padx=10, fill=tk.X)

tk.Label(filter_frame, text="Filtre :").pack(side=tk.LEFT, padx=(0, 10))
self.filter_var = tk.StringVar(value="all")

tk.Radiobutton(filter_frame, text="Toutes", variable=self.filter_var, 
               value="all", command=self.refresh_task_list).pack(side=tk.LEFT, padx=5)
tk.Radiobutton(filter_frame, text="Actives", variable=self.filter_var, 
               value="active", command=self.refresh_task_list).pack(side=tk.LEFT, padx=5)
tk.Radiobutton(filter_frame, text="Terminées", variable=self.filter_var, 
               value="completed", command=self.refresh_task_list).pack(side=tk.LEFT, padx=5)

Dans refresh_task_list : self.filter_mode = self.filter_var.get().

Google AdInline article slot

get_sorted_tasks filtre d'abord par statut, puis trie les tâches actives par ID en haut, terminées en bas :

def get_sorted_tasks(self):
    if self.filter_mode == "active":
        filtered_tasks = [task for task in self.tasks if not task["completed"]]
    elif self.filter_mode == "completed":
        filtered_tasks = [task for task in self.tasks if task["completed"]]
    else:
        filtered_tasks = self.tasks.copy()
    
    active_tasks = [task for task in filtered_tasks if not task["completed"]]
    completed_tasks = [task for task in filtered_tasks if task["completed"]]
    
    active_tasks.sort(key=lambda x: x["id"])
    completed_tasks.sort(key=lambda x: x["id"])
    
    return active_tasks + completed_tasks

Recherche en Temps Réel par Texte de Tâche

Un champ de recherche avec liaison <KeyRelease> permet un filtrage instantané en plus du filtre de statut. Un bouton Effacer réinitialise la requête.

Dans create_widgets, ajoutez search_frame :

Google AdInline article slot
search_frame = tk.Frame(self.root)
search_frame.pack(pady=(0, 5), padx=10, fill=tk.X)

tk.Label(search_frame, text="Recherche :").pack(side=tk.LEFT, padx=(0, 5))
self.search_entry = tk.Entry(search_frame, font=("Arial", 10))
self.search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
self.search_entry.bind("<KeyRelease>", lambda event: self.refresh_task_list())

clear_btn = tk.Button(search_frame, text="✖", command=self.clear_search, width=3)
clear_btn.pack(side=tk.RIGHT, padx=(5, 0))

clear_search vide self.search_entry et appelle refresh_task_list.

get_sorted_tasks s'étend avec un second filtre par search_text = self.search_entry.get().strip().lower() :

search_text = self.search_entry.get().strip().lower()
if search_text:
    filtered_tasks = [task for task in filtered_tasks if search_text in task["text"].lower()]

La recherche est insensible à la casse et s'applique après le filtrage par statut.

  • Avantages de la recherche en temps réel : Latence minimale grâce aux compréhensions de listes.
  • Limites : Recherche linéaire O(n), adaptée à <1000 tâches.
  • Optimisation : Pour des listes plus grandes, envisagez bisect ou indexation externe.

Export des Données Filtrées vers CSV

L'export capture la vue actuelle de la liste (après tous les filtres/recherches). Utilise csv.writer avec BOM UTF-8 pour compatibilité Excel. Délimiteur point-virgule, en-têtes : ID, Texte, Statut, Priorité, Date de Création.

Bouton dans bottom_frame :

self.export_button = tk.Button(bottom_frame, text="📎 Exporter en CSV", command=self.export_to_csv, bg="light cyan")
self.export_button.pack(side=tk.LEFT, padx=5)

export_to_csv :

import csv
from tkinter import filedialog

def export_to_csv(self):
    tasks_to_export = self.get_sorted_tasks()
    if not tasks_to_export:
        messagebox.showinfo("Info", "Aucune tâche à exporter")
        return
    
    filename = filedialog.asksaveasfilename(
        defaultextension=".csv",
        filetypes=[("Fichiers CSV", "*.csv"), ("Tous fichiers", "*.*")],
        title="Enregistrer en CSV"
    )
    if not filename:
        return
    
    try:
        with open(filename, 'w', encoding='utf-8-sig', newline='') as f:
            writer = csv.writer(f, delimiter=';')
            writer.writerow(['ID', 'Texte', 'Statut', 'Priorité', 'Créée'])
            
            for task in tasks_to_export:
                status = "Terminée" if task["completed"] else "Active"
                try:
                    created = datetime.fromisoformat(task["created_at"])
                    date_str = created.strftime("%d.%m.%Y %H:%M:%S")
                except:
                    date_str = task["created_at"]
                priority_map = {"high": "Haute", "medium": "Moyenne", "low": "Basse"}
                priority_display = priority_map.get(task["priority"], task["priority"])
                
                writer.writerow([task["id"], task["text"], status, priority_display, date_str])
        
        messagebox.showinfo("Succès", f"Tâches exportées vers :
{filename}")
    except Exception as e:
        messagebox.showerror("Erreur", f"Échec de l'enregistrement : {e}")

Points Clés

  • Intégration Combobox pour les priorités simplifie l'UX sans popups.
  • Filtrage combiné (statut + recherche) exploite les compréhensions de listes en chaîne pour la rapidité.
  • Export CSV avec UTF-8-sig et ';' fonctionne parfaitement avec Excel sous Windows.
  • Mises à jour en temps réel via les liaisons <KeyRelease> et commandes Radiobutton.
  • Tri priorise toujours les tâches actives en haut.

— Editorial Team

Advertisement 728x90

Lire ensuite