You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tkinter打字计数器问题:计时时无法在Entry输入框输入

解决Tkinter打字测速脚本中倒计时时输入框无法输入的问题

你的推测完全正确——问题出在start_timer函数的while循环和time.sleep(1)上。Tkinter的GUI事件循环运行在主线程中,当你点击按钮触发start_timer后,这个函数会持续占用主线程,time.sleep会让主线程暂停响应,导致输入框的键盘事件无法被处理,所以出现无法输入的情况。

下面提供两种可行的解决思路:

方法一:使用Tkinter内置的after()方法(推荐)

Tkinter提供的after()方法是处理定时任务的标准方式,它可以在指定延迟后执行回调函数,不会阻塞主线程。我们可以用它重构倒计时逻辑:

修改后的start_timer函数:

def start_timer(t=TIMER):
    if t > 0:
        minutes, seconds = divmod(t, 60)
        timer = "{:02d}:{:02d}".format(minutes, seconds)
        canvas.itemconfig(timer_text, text=timer)
        # 1000毫秒(1秒)后递归调用自身,实现倒计时
        window.after(1000, start_timer, t-1)
    else:
        # 倒计时结束后计算WPM
        global generated_text
        inputted_user_text = typed_entry_box.get()
        check_wpm(generated_text, inputted_user_text)

这个方法完全贴合Tkinter的事件驱动模型,不会阻塞主线程,输入框就能正常接收用户输入了。

方法二:使用线程(需注意GUI线程安全)

如果偏好使用线程实现,必须牢记Tkinter的所有GUI操作必须在主线程执行,子线程中不能直接修改GUI元素,需要通过after()将GUI更新操作调度到主线程:

修改后的相关函数和按钮配置:

def update_timer_display(t):
    # 这个函数在主线程执行,负责更新计时器显示
    minutes, seconds = divmod(t, 60)
    timer = "{:02d}:{:02d}".format(minutes, seconds)
    canvas.itemconfig(timer_text, text=timer)

def timer_thread():
    # 子线程中执行倒计时循环
    t = TIMER
    while t > 0:
        # 用after调度GUI更新到主线程
        window.after(0, update_timer_display, t)
        time.sleep(1)
        t -= 1
    # 倒计时结束后,调度结果计算到主线程
    window.after(0, calculate_wpm)

def calculate_wpm():
    # 在主线程中计算并显示WPM
    global generated_text
    inputted_user_text = typed_entry_box.get()
    check_wpm(generated_text, inputted_user_text)

# 修改按钮的command为启动线程
start_timer_button = Button(text="Start Timer", command=lambda: Thread(target=timer_thread).start(), font=(FONT_NAME, 16, FONT_TYPE))

这种方法把耗时的循环和sleep放到子线程,GUI操作通过after()交回主线程执行,同样能解决输入框卡死的问题,但相比方法一复杂度更高。

完整修改后的代码(方法一版本)

# --------------------------------------------------Import Modules-----------------------------------------------------#
from tkinter import *
import time
import random
from threading import Thread

# --------------------------------------------------Set CONSTANTS------------------------------------------------------#
TIMER = 10
FONT_NAME = "Arial"
FONT_HEIGHT = 12
FONT_TYPE = "bold"
BACKGROUND_COLOR = "#A5C9CA"

# --------------------------------------------------Random Text.-------------------------------------------------------#
example_text = [
    "This is going to be a lot of sample text.",
    "This should hopefully be even more sample text."
]


def start_timer(t=TIMER):
    if t > 0:
        minutes, seconds = divmod(t, 60)
        timer = "{:02d}:{:02d}".format(minutes, seconds)
        canvas.itemconfig(timer_text, text=timer)
        # 1000毫秒后递归调用自身,实现倒计时
        window.after(1000, start_timer, t-1)
    else:
        # 倒计时结束后读取输入文本并计算WPM
        global generated_text
        inputted_user_text = typed_entry_box.get()
        check_wpm(generated_text, inputted_user_text)


def generate_text():
    random_text = random.choice(example_text)
    return random_text


def check_wpm(initial_text, inputted_text):
    initial_list = initial_text.split()
    inputted_list = inputted_text.split()
    del initial_list[len(inputted_list):]
    compared_list = [i == j for i, j in zip(initial_list, inputted_list)]
    wpm = 0
    for n in compared_list:
        if n:
            wpm += 1
    wpm_label.config(text=f"You typed at {wpm} words per minute.")


# 初始化窗口
window = Tk()
window.title("WPM Test")
window.config(pady=20, padx=20, bg=BACKGROUND_COLOR)

# 创建画布和计时器文本
canvas = Canvas(width=500, height=500, bg=BACKGROUND_COLOR, highlightthickness=0)
timer_text = canvas.create_text(250, 25, text="00:10", fill="black", font=(FONT_NAME, 18, FONT_TYPE))
canvas.grid(column=0, row=5)

# 说明标签
label_1 = "Test Your Typing Speed. Click the button below and type out the text string shown below. Good Luck!\n" \
          "---------------------------------------------------------------------------------------------------\n\n"
instructions_label = Label(text=label_1, font=(FONT_NAME, 14, FONT_TYPE), bg=BACKGROUND_COLOR)
instructions_label.config(padx=5, pady=5)
instructions_label.grid(row=0, column=0)

# 随机文本标签
generated_text = generate_text()
random_text_label = Label(text=generated_text, font=(FONT_NAME, 18, FONT_TYPE), bg=BACKGROUND_COLOR)
random_text_label.config(padx=5, pady=5)
random_text_label.grid(row=2, column=0)

# 输入提示标签
label_3 = "\n\n-----------------------------------------------------------------------\n\n\n" \
          "Click the button below to start the timer and immediately start typing.\n"
start_typing_label = Label(text=label_3, font=(FONT_NAME, 14, FONT_TYPE), bg=BACKGROUND_COLOR)
start_typing_label.grid(row=3, column=0)

# 启动计时器按钮
start_timer_button = Button(text="Start Timer", command=start_timer, font=(FONT_NAME, 16, FONT_TYPE))
start_timer_button.config(padx=2, pady=2)
start_timer_button.grid(row=4, column=0)

# 用户输入框
typed_entry_box = Entry(width=100, font=(FONT_NAME, 16, FONT_TYPE), bd=5)
typed_entry_box.grid(row=5, column=0)

# WPM结果标签
wpm_label = Label(text="", font=(FONT_NAME, 14, FONT_TYPE), bg=BACKGROUND_COLOR)
wpm_label.grid(row=6, column=0)

# 启动窗口事件循环
window.mainloop()

内容的提问来源于stack exchange,提问作者sgtdiddlywink

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 00:10:36