Tkinter开发打字速度App如何暂停循环等待用户按指定键
问题核心原因
你现在用for循环+time.sleep()的写法本身就会阻塞Tkinter的主事件循环。Tkinter是事件驱动模型,长循环跑在主线程里会直接卡住界面,没法响应键盘输入,之前用按钮+wait_variable体验差本质也是没顺着事件驱动的思路设计逻辑。
最优实现思路
完全抛弃一次性跑完的for循环逻辑,改用状态指针+键盘事件绑定的方案:
- 维护一个当前高亮单词的索引指针,初始值为0
- 单独写一个高亮当前单词的方法,每次调用只高亮指针对应的单词
- 给输入框绑定空格键按下事件,触发时依次完成:校验当前输入的单词是否正确、清除上一个单词的高亮、指针+1、调用高亮方法渲染下一个单词,直到指针走到单词列表末尾结束流程
- 不需要额外的等待逻辑、不需要阻塞循环,所有流程靠用户的键盘输入事件驱动,完全符合GUI程序的运行逻辑,也不会出现界面卡顿的问题。
可直接复用的修改代码
删掉原来type_and_check里的for循环,修改对应类方法即可,不需要额外引入第三方键盘监听库:
import tkinter from tkinter import * import time class TypingSpeedApp: def __init__(self): self.typing_speed_app = Tk() self.typing_speed_app.title("Typing Speed Application") self.typing_speed_app.minsize(1200, 700) self.typing_speed_app.resizable(False, False) # define background image self.background_image = PhotoImage(file="background_image.PNG") # create canvas self.canvas = Canvas(self.typing_speed_app, width=1200, height=700) self.canvas.pack(fill="both", expand=True) # set image in canvas self.canvas.create_image(0, 0, image=self.background_image, anchor="nw") # add a label self.canvas.create_text(590, 50, text="Welcome to typing speed application", font=("Helvetica", 30), fill="white") # add a label self.canvas.create_text(130, 90, text="Base text:", font=("Helvetica", 20), fill="white", state=DISABLED) # Define Entry Boxes self.base_text = Text(self.typing_speed_app, font=("Helvetica", 24), width=60, height=2, bd=0, wrap=tkinter.WORD) self.base_text_window = self.canvas.create_window(70, 120, anchor="nw", window=self.base_text) # add a label self.canvas.create_text(130, 220, text="Type here:", font=("Helvetica", 20), fill="white") # Define Entry Boxes self.type_text = Text(self.typing_speed_app, font=("Helvetica", 24), width=20, height=1, bd=0, wrap=tkinter.WORD) self.type_text_window = self.canvas.create_window(70, 250, anchor="nw", window=self.type_text) # add a label self.canvas.create_text(510, 220, text="Timer:", font=("Helvetica", 20), fill="white") # Define Entry Boxes self.time_text = Text(self.typing_speed_app, font=("Helvetica", 24), width=5, height=1, bd=0, background="green") self.time_text_window = self.canvas.create_window(470, 250, anchor="nw", window=self.time_text) # text get from base_text self.base_text_get_test = "" # this list contain indexes of spaces self.space_indexes = ["1.0"] # 新增:当前高亮单词的指针 self.current_word_idx = 0 # 新增:提前拆分好基准文本的单词列表,方便校验 self.word_list = [] # 给输入框绑定空格键事件,仅输入框聚焦时触发,避免全局快捷键冲突 self.type_text.bind('<space>', self.on_space_press) # show gui def main_loop(self): self.typing_speed_app.mainloop() def read_text_file(self): with open('text_1.txt') as text_file: lines = str(text_file.readlines()) content = lines[2:-2] + " " self.base_text.insert(tkinter.END, content) self.base_text.configure(state=DISABLED) self.base_text_get_test = self.base_text.get("1.0", tkinter.END).strip() # 拆分单词列表,过滤空字符串 self.word_list = [w for w in self.base_text_get_test.split(" ") if w] def find_space_intervals(self): idx = '1.0' while 1: idx = self.base_text.search(" ", idx, stopindex=END) if not idx: break last_idx = '%s+%dc' % (idx, 1) self.space_indexes.append(idx) self.space_indexes.append(last_idx) idx = last_idx def highlight_current_word(self): # 所有单词遍历完成直接结束 if self.current_word_idx * 2 >= len(self.space_indexes) -1: # 此处可添加打字完成后的结算逻辑,比如计算WPM、弹出结果提示 return start = self.space_indexes[self.current_word_idx * 2] end = self.space_indexes[self.current_word_idx * 2 + 1] self.base_text.tag_add("select", start, end) self.base_text.tag_configure("select", background="gray") self.base_text.see(start) def on_space_press(self, event): # 获取用户当前输入的内容,去掉首尾空格 input_content = self.type_text.get("1.0", END).strip() # 清空输入框,准备下一个单词输入 self.type_text.delete("1.0", END) # 移除上一个单词的高亮 prev_start = self.space_indexes[self.current_word_idx *2] prev_end = self.space_indexes[self.current_word_idx *2 +1] self.base_text.tag_remove("select", prev_start, prev_end) # 此处可添加输入校验逻辑:对比input_content和self.word_list[self.current_word_idx],输入错误可做标红提示 # 指针后移,高亮下一个单词 self.current_word_idx +=1 self.highlight_current_word() # 返回break可阻止空格输入到文本框,不需要可以删除 return "break" def type_and_check(self): # 初始化时只高亮第一个单词即可 self.highlight_current_word()
注意:原有
main.py的调用逻辑无需修改,保持原有执行顺序即可正常运行。
额外优化点
- 去掉第三方
keyboard库的全局监听逻辑,直接绑定Tkinter组件的<space>事件即可,不会误触其他软件的快捷键 - 可以在校验逻辑里增加对错反馈:输入正确单词高亮绿色,错误高亮红色,交互体验更好
- 计时逻辑可以绑定在第一个单词输入时自动启动,不需要额外点击按钮触发
- 原有读取文件的逻辑直接转
str(readlines())会带列表括号和转义字符,建议改成逐行拼接后再处理,避免特殊字符混进待打字文本中
内容的提问来源于stack exchange,提问作者waxier358
相关产品推荐
相关产品推荐

