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

TKinter打字测速软件中Label组件清除问题求助

问题分析与修复方案

核心错误点

  1. clear方法调用参数错误:reset方法里调用self.clear(self),但clear方法定义为def clear(self):,无需额外传self参数,这会触发参数数量不匹配的报错。
  2. after方法使用错误:clear方法里self.sample_label.after(1000, self.sample_label.destroy())直接执行了destroy方法,正确写法是传递函数对象self.sample_label.destroy(不带括号),否则控件会被立即销毁,而非延迟1秒执行。
  3. 控件重复创建问题:reset和test_name方法里每次都新建Label控件,未先销毁旧控件,导致界面控件重叠且浪费资源。

修复步骤

  • 修正clear方法的调用方式,删除多余的self参数。
  • 修复after方法的函数传递逻辑,去掉destroy后的括号。
  • 优化控件更新逻辑:不再重复创建Label,直接修改现有sample_label的text属性,避免控件重叠。
  • 优化文件读取逻辑:用with语句确保文件正确关闭,初始化时一次性读取所有文本内容,避免重复打开文件。

修改后的完整代码

import tkinter as tk 
import time 
import threading 
import random 

class TypeSpeedGUI: 
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Type Speed App")
        self.root.geometry("800x600")

        self.levelsel = 0
        
        # 初始化时读取所有文本文件内容
        with open("start.txt", "r") as f:
            self.text_start = f.read().split("\n")
        with open("texts1.txt", "r") as f:
            self.text_level1 = f.read().split("\n")
        with open("texts2.txt", "r") as f:
            self.text_level2 = f.read().split("\n")
        with open("texts3.txt", "r") as f:
            self.text_level3 = f.read().split("\n")

        self.frame = tk.Frame(self.root)

        self.sample_label = tk.Label(self.frame, text=random.choice(self.text_start), font=("Helvetica", 18))
        self.sample_label.grid(row=1, column=3, columnspan=2, padx=5, pady=5)

        self.input_entry = tk.Entry(self.frame, width=40, font=("Helvetica", 24))
        self.input_entry.grid(row=2, column=3, columnspan=2, padx=5, pady=10)
        self.input_entry.bind("<KeyPress>", self.start)

        self.speed_label = tk.Label(self.frame, text="Speed: \n0.00 CPS\n0.00 CPM\n0.00 WPM\n0.00 WPS", font=("Helvetica", 18))
        self.speed_label.grid(row=4, column=3, columnspan=2, padx=5, pady=10)
        
        self.reset_button = tk.Button(self.frame, text="Reset", command=self.reset)
        self.reset_button.grid(row=5, column=3, columnspan=2, padx=5, pady=10)

        self.level1_button = tk.Button(self.frame, text="Level 1", command=self.level1)
        self.level1_button.grid(row=0, column=2, columnspan=2, padx=5, pady=10)

        self.level2_button = tk.Button(self.frame, text="Level 2", command=self.level2)
        self.level2_button.grid(row=0, column=3, columnspan=2, padx=5, pady=10)

        self.level3_button = tk.Button(self.frame, text="Level 3", command=self.level3)
        self.level3_button.grid(row=0, column=4, columnspan=2, padx=5, pady=10)

        self.frame.pack(expand=True)

        self.counter = 0 
        self.started = False

        self.root.mainloop()

    def start(self, event):
        if not self.started: 
            if event.keycode not in [16, 17, 18]: 
                self.started = True 
                t = threading.Thread(target=self.time_thread)
                t.daemon = True  # 设置守护线程,关闭窗口时自动退出
                t.start()
        input_text = self.input_entry.get()
        sample_text = self.sample_label.cget("text")
        if not sample_text.startswith(input_text):
            self.input_entry.config(fg="red")
        else:
            self.input_entry.config(fg="black")
        if input_text == sample_text[:-1]:
            self.started = False 
            self.input_entry.config(fg="green")
                        

    def time_thread(self):
        while self.started:
            time.sleep(0.1)
            self.counter += 0.1 
            input_text = self.input_entry.get()
            cps = len(input_text) / self.counter
            cpm = cps * 60
            wps = len(input_text.split()) / self.counter
            wpm = wps * 60
            self.speed_label.config(text=f"Speed: \n{cps:.2f} CPS\n{cpm:.2f} CPM\n{wps:.2f} WPS\n{wpm:.2f} WPM")

    def level1(self):
        self.levelsel = 1
        self.update_sample_text(self.text_level1)
    
    def level2(self):
        self.levelsel = 2
        self.update_sample_text(self.text_level2)

    def level3(self):
        self.levelsel = 3
        self.update_sample_text(self.text_level3)

    def reset(self):
        self.clear()
        self.update_sample_text(self.text_start)
        self.started = False 
        self.counter = 0 
        self.speed_label.config(text="Speed: \n0.00 CPS\n0.00 CPM\n0.00 WPM\n0.00 WPS")
        self.input_entry.delete(0, tk.END)
        self.input_entry.config(fg="black")
    
    def update_sample_text(self, text_list):
        # 直接修改现有label的文本,无需重新创建
        self.sample_label.config(text=random.choice(text_list))
        # 根据等级调整布局
        if self.levelsel in [1,2,3]:
            self.sample_label.grid(row=1, column=3, columnspan=5, padx=5, pady=5)
        else:
            self.sample_label.grid(row=1, column=3, columnspan=2, padx=5, pady=5)

    def clear(self):
        # 延迟1秒销毁控件,若需清空文本可替换为lambda: self.sample_label.config(text="")
        self.sample_label.after(1000, self.sample_label.destroy)

TypeSpeedGUI() 

额外优化说明

  • 用with语句读取文件,避免资源泄漏。
  • 给线程设置daemon=True,关闭窗口时线程自动退出。
  • 提取update_sample_text方法统一处理文本更新,减少重复代码。
  • 简化条件判断写法,提升代码可读性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 01:54:54