Tkinter闪卡应用无法切换加载文件的技术问题
CustomTkinter闪卡应用文件切换崩溃问题修复
问题现象
基于CustomTkinter开发的闪卡测验应用,启动时能正常读取Python脚本所在目录下Text文件夹内的txt文件,但切换文件时(无论是切换到新文件还是原文件)都会触发FileNotFoundError,无法找到目标文件。
错误根源
问题出在getFiles()函数中的os.chdir("../Code/Text")语句:
- 应用启动时,当前工作目录是脚本所在的
Code文件夹,此时Text/文件名的相对路径有效 - 调用
os.chdir后,当前工作目录被切换到Text文件夹,后续FileHandling函数仍用Text/文件名的路径,实际会去Text/Text/文件名找文件,自然不存在
修复方案
避免修改当前工作目录,改用绝对路径定位Text文件夹,确保无论何时都能正确找到文件:
- 获取当前脚本所在的绝对目录
- 拼接出
Text文件夹的绝对路径 - 用绝对路径读取文件和遍历txt文件
修复后的完整代码
from customtkinter import * from CTkMessagebox import CTkMessagebox import glob import os information = [] file_name = 'keywords.txt' app = None # 获取当前脚本所在目录的绝对路径 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 拼接Text文件夹的绝对路径 TEXT_DIR = os.path.join(BASE_DIR, "Text") def hide(tk): # 隐藏窗口 try: tk.withdraw() except: pass def show(tk): # 显示窗口 tk.deiconify() def FileHandling(filename): # 文件读取处理 information = [] # 使用绝对路径打开文件 file_path = os.path.join(TEXT_DIR, filename) with open(file_path, 'r', encoding='utf-8') as f: temp = f.read().split("\n") for i in range(0, len(temp), 2): if i+1 >= len(temp): break # 避免最后一行只有单个内容导致索引越界 temp_list = [] temp_list.append(temp[i].capitalize()) temp_list.append(temp[i+1].capitalize()) information.append(temp_list) return information def changeHandler(value): global file_name file_name = value print(value) return file_name def changeFile(): # 切换文件逻辑 files = getFiles() filePicker(files) def getFiles(): temp = [] # 遍历Text文件夹下的txt文件,无需切换目录 for file in glob.glob(os.path.join(TEXT_DIR, "*.txt")): # 只保留文件名,不保留路径 temp.append(os.path.basename(file)) return temp def filePicker(files): hide(app) FilePicker = CTkToplevel() FilePicker.geometry("500x400") FilePicker.resizable(False, False) FilePicker.title("文件选择器") Title = CTkLabel( master=FilePicker, text="选择要加载的文件", font=("Arial", 10)) Title.place(relx=0.5, rely=0.05, anchor="center") Options = CTkComboBox(FilePicker, values=files, variable="未选择", command=changeHandler) # type: ignore Options.place(relx=0.5, rely=0.5, anchor="center") ExitBtn = CTkButton(master=FilePicker, text="返回菜单", fg_color="#550000", text_color="#000000", command=lambda: Menu(FilePicker)).place(relx=0.5, rely=0.7, anchor="center") def Menu(tk=None): global information information = FileHandling(file_name) global app # 创建主窗口或显示已存在的窗口 if app == None: app = CTk() app.geometry("500x400+750+300") app.resizable(False, False) app.title("闪卡应用") set_appearance_mode("dark") Title = CTkLabel(master=app, text="闪卡项目", font=("Arial", 40)) PlayBtn = CTkButton(master=app, text="开始测验", fg_color="#005500", text_color="#000000", command=lambda: Run(app)) Changebtn = CTkButton(master=app, text="切换文件", fg_color="#AA4203", text_color="#000000", command=changeFile) ExitBtn = CTkButton(master=app, text="退出", fg_color="#550000", text_color="#000000", command=app.quit) Title.place(relx=0.5, rely=0.05, anchor="center") PlayBtn.place(relx=0.5, rely=0.4, anchor="center") Changebtn.place(relx=0.5, rely=0.5, anchor="center") ExitBtn.place(relx=0.5, rely=0.6, anchor="center") app.mainloop() exit() else: show(app) try: tk.destroy() except: pass # 补充Run函数(原代码中未定义,避免报错) def Run(tk): hide(tk) # 这里可以添加闪卡测验的逻辑 TestWindow = CTkToplevel() TestWindow.geometry("500x400") TestWindow.title("闪卡测验") # 示例标签 Label(TestWindow, text="闪卡测验界面").pack(pady=20) # 返回菜单按钮 CTkButton(TestWindow, text="返回菜单", command=lambda: [hide(TestWindow), Menu()]).pack(pady=10) Menu()
额外优化点
- 增加了文件读取时的编码指定(
encoding='utf-8'),避免中文乱码 - 处理了txt文件最后一行可能只有单个内容的情况,防止索引越界
- 补充了原代码中缺失的
Run函数,避免点击"开始"按钮时报错 - 把界面文本改成了中文,更符合使用习惯
内容的提问来源于stack exchange,提问作者C0d3_404
相关产品推荐
相关产品推荐

