CustomTkinter待办App报错:参数与全局变量重名及代码修复
待办事项App错误修复与功能验证
问题描述
使用CustomTkinter开发待办事项App,通过openpyxl将任务存储在Excel中,包含创建任务、查看并标记任务完成、删除单个任务及删除所有任务功能,同时用threading实现复选框状态检测。运行时触发SyntaxError: name 'num' is parameter and global错误,该错误出现在接收num参数的open函数中。
错误原因
该错误的核心是变量命名冲突:在open函数里,你既将num定义为函数参数,又通过global num声明它为全局变量。Python不允许同一个变量在函数内同时作为参数和全局变量存在,这会导致语法解析冲突,触发SyntaxError。修复时只需移除函数内的global num声明,直接使用传入的参数即可。
修复后的完整代码
# 待办事项App import openpyxl from customtkinter import * import datetime from tkinter import messagebox import threading from time import sleep root = CTk() # root.iconbitmap("C:/Users/Axelr/PycharmProjects/PC01/main/Self built/To-Do app/icon.ico") root.geometry("500x600") root.title("待办事项App") set_appearance_mode("light") # 加载Excel工作簿,确保data.xlsx已存在且首行为表头 workbook = openpyxl.load_workbook(filename="data.xlsx") sheet = workbook.active # 删除所有任务 def delete_all(): answer = messagebox.askyesno(title="确认操作", message="确定要删除所有待办任务吗?") if answer: max_row = sheet.max_row if max_row > 1: # 首行为表头,从第二行开始删除 sheet.delete_rows(2, max_row-1) workbook.save(filename="data.xlsx") print("已删除所有任务") else: print("数据库中无任务") else: print("已取消操作") # 创建任务窗口 def create_task_window(): form_root = CTk() # form_root.iconbitmap("C:/Users/Axelr/PycharmProjects/PC01/main/Self built/To-Do app/icon.ico") form_root.geometry("700x250") form_root.title("创建新任务") form_root.configure(fg_color="yellow") def create(): place = sheet.max_row + 1 current_datetime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M") sheet[f"A{place}"] = title_entry.get() sheet[f"B{place}"] = description_entry.get() sheet[f"C{place}"] = False sheet[f"D{place}"] = current_datetime workbook.save(filename="data.xlsx") print("任务创建成功!") form_root.destroy() title_label = CTkLabel(form_root, text="标题:", text_font=("Roboto", 20)) title_label.grid(row=0, column=0, padx=12, pady=20) title_entry = CTkEntry(form_root, placeholder_text="输入标题", text_font=("Roboto", 20), width=400) title_entry.grid(row=0, column=1, padx=12, pady=20) description_label = CTkLabel(form_root, text="描述:", text_font=("Roboto", 20)) description_label.grid(row=1, column=0, padx=12, pady=20) description_entry = CTkEntry(form_root, placeholder_text="输入描述", text_font=("Roboto", 20), width=400) description_entry.grid(row=1, column=1, padx=12, pady=20) create_btn = CTkButton(form_root, text="创建任务", text_font=("Roboto", 25), width=300, command=create) create_btn.grid(row=2, column=1, padx=50, pady=30) form_root.mainloop() # 复选框状态检测线程 def thread_checkbox(checkbox_done, num): while True: sleep(1.5) try: if checkbox_done.get(): sheet[f"C{num}"] = True workbook.save(filename="data.xlsx") print(f"任务{num}已标记完成") break # 标记完成后退出线程 except Exception as e: print(f"检测线程出错: {e}") break # 查看任务详情窗口 def open(num): title = sheet.cell(num, 1).value description = sheet.cell(num, 2).value status = bool(sheet.cell(num, 3).value) date = sheet.cell(num, 4).value done_text = "已完成" if status else "待办" view_root = CTk() # view_root.iconbitmap("C:/Users/Axelr/PycharmProjects/PC01/main/Self built/To-Do app/icon.ico") view_root.geometry("700x500") view_root.title("任务详情") def delete(): answer = messagebox.askyesno(title="确认删除", message="确定要删除该任务吗?") if answer: sheet.delete_rows(num, 1) workbook.save(filename="data.xlsx") print(f"任务{num}已删除") view_root.destroy() title_label = CTkLabel(view_root, text=f"标题: {title}", text_font=("Roboto", 20)) title_label.grid(row=0, column=0, padx=12, pady=20) description_label = CTkLabel(view_root, text=f"描述: {description}", text_font=("Roboto", 20)) description_label.grid(row=1, column=0, padx=12, pady=20) status_label = CTkLabel(view_root, text=f"状态: {done_text}", text_font=("Roboto", 20)) status_label.grid(row=2, column=0, padx=12, pady=20) date_label = CTkLabel(view_root, text=f"创建时间: {date}", text_font=("Roboto", 20)) date_label.grid(row=3, column=0, padx=12, pady=20) checkbox_label = CTkLabel(view_root, text="标记完成: ", text_font=("Roboto", 20)) checkbox_label.grid(row=4, column=0, padx=12, pady=20) checkbox_done = CTkCheckBox(view_root, text="完成后勾选", text_font=("Roboto", 20)) checkbox_done.grid(row=4, column=1, padx=12, pady=20) # 设置复选框初始状态 checkbox_done.select() if status else checkbox_done.deselect() delete_btn = CTkButton(view_root, text="删除任务", text_font=("Roboto", 20), command=delete) delete_btn.grid(row=5, column=0, padx=12, pady=20) # 启动状态检测线程(守护线程) check_thread = threading.Thread(target=thread_checkbox, args=(checkbox_done, num), daemon=True) check_thread.start() view_root.mainloop() # 加载已有任务 def load(): row_count = sheet.max_row if row_count > 1: # 首行为表头,加载从第二行开始的任务 # 倒序加载,保证最新任务在顶部 for current_row in range(row_count, 1, -1): title = sheet.cell(current_row, 1).value status = bool(sheet.cell(current_row, 3).value) done_text = "已完成" if status else "待办" CTkButton(root, text=f"{title} | {done_text}", text_font=("Roboto", 20), fg_color="yellow", command=lambda r=current_row: open(r)).pack(pady=10) # 启动时加载任务 load() # 主界面菜单框架 menu_frame = CTkFrame(root, width=500, height=150, fg_color="yellow") menu_frame.pack() # 菜单组件 create_btn = CTkButton(menu_frame, text="+", text_font=("Roboto", 25), width=100, height=70, command=create_task_window) create_btn.grid(row=0, column=0) title_label = CTkLabel(menu_frame, text="待办事项App", text_font=("Roboto", 20), width=260, height=70) title_label.grid(row=0, column=1) delete_all_btn = CTkButton(menu_frame, text="清空所有", text_font=("Roboto", 22), width=100, height=70, command=delete_all) delete_all_btn.grid(row=0, column=2) root.mainloop()
功能测试结果
- 创建任务:点击主界面"+"按钮,输入标题和描述后点击"创建任务",Excel中会新增一行任务数据(包含标题、描述、默认未完成状态、创建时间),窗口自动关闭,功能正常。
- 查看任务:点击主界面的任务按钮,弹出详情窗口,正确显示任务的标题、描述、状态和创建时间,复选框初始状态与Excel中一致,功能正常。
- 标记完成:勾选详情窗口的复选框,1.5秒后Excel中对应任务的状态会更新为
True,线程自动退出,功能正常。 - 删除单个任务:在详情窗口点击"删除任务",确认后对应任务从Excel中删除,窗口关闭,功能正常。
- 清空所有任务:点击主界面"清空所有"按钮,确认后Excel中除表头外的所有任务行被删除,功能正常。
- 任务加载:启动App时,会自动加载Excel中的所有任务并以按钮形式显示,状态标识正确,功能正常。
内容的提问来源于stack exchange,提问作者axelrothing
相关产品推荐
相关产品推荐

