返回首页

Tkinter ToDo:搜索过滤 CSV 导出

本文描述了 Tkinter ToDo 的扩展:添加用于优先级的 Combobox、单选按钮过滤、实时搜索和 CSV 导出。包含带 UTF-8 处理和排序的方法的完整代码。

Tkinter ToDo 应用中的过滤器和数据导出
Advertisement 728x90

Tkinter 待办事项应用:筛选、搜索与 CSV 导出

将优先级选择直接集成到输入面板,能显著加速任务创建。我们用 ttk.Combobox 替换模态对话框,提供高、中、低三个选项。支持回车键添加,进一步优化工作流。

create_widgets 中添加包含 Entry、Combobox 和按钮的框架:

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="优先级:").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="➕ 添加", command=self.add_task, bg="light blue")
self.add_button.pack(side=tk.RIGHT)

add_task 方法简化处理:从 self.entryself.priority_var.get() 获取数据,保存任务,清空输入框,并刷新列表。

Google AdInline article slot

按状态筛选任务

单选按钮切换视图:显示全部任务、仅活动任务或仅完成任务。筛选逻辑集成到 get_sorted_tasks 中。

__init__ 中添加 self.filter_mode = "all"。在 create_widgets 中添加筛选面板和单选按钮:

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

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

tk.Radiobutton(filter_frame, text="全部", variable=self.filter_var, 
               value="all", command=self.refresh_task_list).pack(side=tk.LEFT, padx=5)
tk.Radiobutton(filter_frame, text="活动", variable=self.filter_var, 
               value="active", command=self.refresh_task_list).pack(side=tk.LEFT, padx=5)
tk.Radiobutton(filter_frame, text="已完成", variable=self.filter_var, 
               value="completed", command=self.refresh_task_list).pack(side=tk.LEFT, padx=5)

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

Google AdInline article slot

get_sorted_tasks 先按状态筛选,再将活动任务按 ID 置顶,完成任务置底排序:

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

实时任务文本搜索

搜索框绑定 <KeyRelease> 事件,实现即时筛选,可叠加状态筛选。清除按钮重置查询。

create_widgets 中添加 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="搜索:").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 清空 self.search_entry 并调用 refresh_task_list

get_sorted_tasks 扩展第二个筛选层: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()]

搜索不区分大小写,在状态筛选后应用。

  • 实时搜索优势: 使用列表推导式,延迟极小。
  • 局限性: 线性 O(n) 搜索,适合 <1000 条任务。
  • 优化建议: 大列表可考虑 bisect 或外部索引。

导出筛选数据到 CSV

导出捕获当前列表视图(应用所有筛选/搜索)。使用 csv.writer 并带 UTF-8 BOM 确保 Excel 兼容。分隔符为分号,表头:ID、文本、状态、优先级、创建日期。

bottom_frame 中添加按钮:

self.export_button = tk.Button(bottom_frame, text="📎 导出 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("提示", "没有任务可导出")
        return
    
    filename = filedialog.asksaveasfilename(
        defaultextension=".csv",
        filetypes=[("CSV 文件", "*.csv"), ("所有文件", "*.*")],
        title="保存为 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', '文本', '状态', '优先级', '创建时间'])
            
            for task in tasks_to_export:
                status = "已完成" if task["completed"] else "活动"
                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": "高", "medium": "中", "low": "低"}
                priority_display = priority_map.get(task["priority"], task["priority"])
                
                writer.writerow([task["id"], task["text"], status, priority_display, date_str])
        
        messagebox.showinfo("成功", f"任务已导出至:\n{filename}")
    except Exception as e:
        messagebox.showerror("错误", f"保存文件失败:{e}")

核心要点

  • Combobox 集成 优先级选择,无需弹窗简化用户体验。
  • 组合筛选(状态 + 搜索)利用链式列表推导式提升速度。
  • CSV 导出 使用 UTF-8-sig 和 ';',Windows Excel 无缝兼容。
  • 实时更新 通过 <KeyRelease> 绑定和单选按钮命令实现。
  • 排序逻辑 始终将活动任务置顶。

— Editorial Team

Advertisement 728x90

继续阅读