CustomTkinter更新帧中文字闪烁故障的排查与解决问询
问题
在CustomTkinter程序中,我用一个标准Tkinter帧来显示地铁线路状态信息,每次通过OptionMenu选择不同线路后,帧会更新内容。但操作1-2次以上后,部分文字出现闪烁故障。我猜测可以通过每次操作时更新帧来解决,但编程基础薄弱,不知道具体怎么实现。相关代码如下:
def linepick(linechoice): if linechoice == "Waterloo & City": linechoice = "waterloo-city" else: None if linechoice == "Hammersmith & City": linechoice = "hammersmith-city" else: None endpoint = f"https://api.tfl.gov.uk/Line/{linechoice}/Status" response = requests.get(endpoint) if response.status_code == 200: data = response.json() if len(data) > 0 and "lineStatuses" in data[0]: linedata1 = data[0]["lineStatuses"][0] if linechoice == "waterloo-city": linechoice = "Waterloo & City" else: None if linechoice == "hammersmith-city": linechoice = "Hammersmith & City" else: None label1 = ct.CTkLabel(frame, text=f'{linechoice} line:{linedata1["statusSeverityDescription"]}', font=("Arial", 16)) label1.place(x=0, y=30) elif response.status_code == 300: redirection = response.headers["location"] rerequest = requests.get(redirection) rerequestdata = rerequest.json() if len(rerequestdata) > 0 and "lineStatuses" in rerequestdata[0]: # 原代码此处存在拼写错误:lineStauses -> lineStatuses linedata2 = rerequestdata[0]["lineStauses"][0] if linechoice == "waterloo-city": linechoice = "Waterloo & City" else: None if linechoice == "hammersmith-city": linechoice = "Hammersmith & City" else: None label2 = ct.CTkLabel(frame, text=f'{linechoice} line:{linedata2["statusSeverityDescription"]}', font=("Arial", 16)) label2.place(x=0, y=30) else: label3 = ct.CTkLabel(frame, text="Status line not reached, try again later.", font=("Arial", 16)) label3.place(x=0, y=30) # 创建OptionMenu stationmenu = ct.CTkOptionMenu( issuewindow, values=["Bakerloo","Waterloo & City","Central","Circle","District","Hammersmith & City","Jubilee","Metropolitan","Northern","Piccadilly","Victoria"], font=("Arial", 20), corner_radius=10, fg_color="#0C56FF", command=linepick) stationmenu.place(x=35, y=40)
解决方案
故障原因
每次选择新线路时,你都在同一位置创建新的CTkLabel控件,旧的Label并没有被销毁。多个Label重叠在一起,界面渲染时会出现短暂的叠加冲突,这就是文字闪烁的根本原因。
解决方法
- 提前创建固定Label:在初始化阶段就创建好用于显示状态的Label,而不是每次请求后新建
- 仅更新Label内容:每次获取到新数据后,只修改已有Label的
text属性 - 优化线路名称转换:用字典映射替代重复的if判断,简化代码逻辑
修改后的代码
# 先在全局或类初始化阶段创建好固定的状态Label(需确保frame已提前创建) status_label = ct.CTkLabel(frame, text="请选择一条线路查看状态", font=("Arial", 16)) status_label.place(x=0, y=30) # 线路名称映射字典,避免重复的if判断,后续新增特殊线路只需在此添加 LINE_NAME_MAP = { "Waterloo & City": "waterloo-city", "Hammersmith & City": "hammersmith-city" } def linepick(linechoice): # 转换线路名称为API要求的格式 api_line_name = LINE_NAME_MAP.get(linechoice, linechoice) endpoint = f"https://api.tfl.gov.uk/Line/{api_line_name}/Status" response = requests.get(endpoint) # 统一处理重定向逻辑,避免重复代码 if response.status_code == 300: redirection = response.headers["location"] response = requests.get(redirection) if response.status_code == 200: data = response.json() if len(data) > 0 and "lineStatuses" in data[0]: linedata = data[0]["lineStatuses"][0] # 把API用的名称转回显示用的名称 display_name = next((k for k, v in LINE_NAME_MAP.items() if v == api_line_name), api_line_name) # 仅更新已有Label的文本内容 status_label.configure(text=f'{display_name} line: {linedata["statusSeverityDescription"]}') else: status_label.configure(text="无法获取线路状态,请稍后重试。") # 创建OptionMenu stationmenu = ct.CTkOptionMenu( issuewindow, values=["Bakerloo","Waterloo & City","Central","Circle","District","Hammersmith & City","Jubilee","Metropolitan","Northern","Piccadilly","Victoria"], font=("Arial", 20), corner_radius=10, fg_color="#0C56FF", command=linepick) stationmenu.place(x=35, y=40)
额外说明
- 修正了原代码中的拼写错误:
lineStauses改为lineStatuses - 用字典映射线路名称,代码更简洁易维护
- 统一处理重定向逻辑,减少冗余代码
- 仅更新已有Label的内容,不会创建新控件,彻底解决闪烁问题
内容的提问来源于stack exchange,提问作者BigJ
相关产品推荐
相关产品推荐

