如何用Python Tkinter实现带文本的Label图片定期更新?
Tkinter定期更新带文本的Label图片
需要实现无手动触发(点击、回车等)的情况下,定期更新Label上的图片——每次在图片上写入新文本并刷新Label。尝试过绑定虚拟事件、使用after方法,但均无效,以下是极简示例代码,求解决方案:
#!/usr/bin/python # -*- coding: utf-8 -*- ''' Display - Show handling hints, minimal example ''' import tkinter import os from PIL import Image, ImageTk, ImageDraw, ImageFont import threading, time import sys root_path = r"some_path" sys.path.append(root_path) import version class Display: def __init__(self): self.base_path_img = os.path.join(root_path, "Images/") self.teststep_image_name = "teststep.jpg" self.teststep_name = "teststep_init" self.button_height = 2 self.button_width = 20 self.window_width = 900 self.teststep_height = 700 self.frame_height = 500 self.logo_height = 50 self.logo_width = 100 self.window_size = str(self.window_width) + "x400" self.grid_columns = 3 # vertical self.grid_rows = 3 # horizontal self.displ = tkinter.Tk() self.displ.maxsize = self.window_width self.teststep_text = "TestStep init" self.step_label_init() self.update_time = 1 self.update_tuple = (self.teststep_image_name, self.teststep_text) self.n_calls = 0 self.displ.after(self.update_time, self.update_img_teststep) self.displ.mainloop() def step_label_init(self): '''Configure Label for Teststep display with image and text''' self.teststep_image = self.open_tk_image(self.teststep_image_name, self.window_width, self.teststep_height, self.teststep_text) self.TestStep_Label = tkinter.Label( self.displ, bg = "white", height = self.frame_height, width = self.window_width, image = self.teststep_image) self.TestStep_Label.grid_configure( row = 2, column = 1, columnspan = 3, sticky = tkinter.NSEW) #variant 2 #self.TestStep_Label.after(1000, self.update_img_teststep, "") def open_tk_image(self, img_name, img_width, img_height, test_text = ""): pil_image = Image.open(self.base_path_img + img_name, "r").resize((img_width, img_height)) img_draw = ImageDraw.Draw(pil_image) textwidth = 20 textheight = 50 x = img_width // 4 - textwidth y = img_height // 5 - textheight img_draw.text((x, y), test_text, fill="yellow", font_size=30) tk_image = ImageTk.PhotoImage(pil_image) pil_image.close() return tk_image def update_img_teststep(self, input_ign=""): #dummy argument print(input_ign) img_name = self.update_tuple[0] teststep_text = self.update_tuple[1] + "number of calls: " + str(self.n_calls) self.teststep_image = self.open_tk_image(img_name, self.window_width, self.teststep_height, teststep_text) self.TestStep_Label.configure(image = self.teststep_image) self.n_calls += 1 def displ_config(self): #test start for i in range(1,3): time.sleep(self.update_time) print(f'slept, now i is {i}') self.update_tuple = ("teststep"+str(i)+".jpg", "this is text #" + str(i)) self.displ.configure(bg = "black") #test end # import time # import threading if __name__ == "__main__": displ = Display()
问题分析与解决方案
你的代码存在几个关键问题,导致更新失效:
after仅执行一次:当前self.displ.after(self.update_time, self.update_img_teststep)只调用一次更新方法,没有形成循环。需要在update_img_teststep末尾再次调用after,实现定期循环更新。- 时间单位错误:
after方法的时间参数单位是毫秒,你设置的self.update_time = 1相当于1毫秒,刷新过快且可能导致主循环阻塞,建议改为1000(1秒)。 time.sleep阻塞主循环:displ_config中的time.sleep会冻结Tkinter主循环,无法处理UI更新,必须改用after来定时修改update_tuple。- 文字大小设置错误:
ImageDraw.text没有font_size参数,需要用ImageFont.truetype加载字体并指定大小,否则文字大小不生效。 - 参数不匹配:
after调用update_img_teststep时没有传参,但方法定义需要input_ign,会导致报错,需给参数设置默认值或传参。
修正后的代码
#!/usr/bin/python # -*- coding: utf-8 -*- import tkinter import os from PIL import Image, ImageTk, ImageDraw, ImageFont import sys root_path = r"some_path" sys.path.append(root_path) import version class Display: def __init__(self): self.base_path_img = os.path.join(root_path, "Images/") self.teststep_image_name = "teststep.jpg" self.teststep_text = "TestStep init" self.window_width = 900 self.teststep_height = 700 self.frame_height = 500 self.displ = tkinter.Tk() self.displ.geometry(f"{self.window_width}x400") # 正确设置窗口大小 self.update_time = 1000 # 单位:毫秒,即1秒 self.update_tuple = (self.teststep_image_name, self.teststep_text) self.n_calls = 0 self.step_label_init() # 启动循环更新 self.displ.after(self.update_time, self.update_img_teststep) # 启动模拟更新update_tuple的定时任务 self.displ.after(2000, self.simulate_update_tuple) self.displ.mainloop() def step_label_init(self): self.teststep_image = self.open_tk_image(self.teststep_image_name, self.window_width, self.teststep_height, self.teststep_text) self.TestStep_Label = tkinter.Label( self.displ, bg = "white", height = self.frame_height, width = self.window_width, image = self.teststep_image) self.TestStep_Label.grid(row=2, column=1, columnspan=3, sticky=tkinter.NSEW) def open_tk_image(self, img_name, img_width, img_height, test_text=""): pil_image = Image.open(os.path.join(self.base_path_img, img_name)).resize((img_width, img_height)) img_draw = ImageDraw.Draw(pil_image) # 正确设置字体大小 try: # 系统默认字体,可替换为自定义字体路径 font = ImageFont.truetype("arial.ttf", 30) except: # fallback到默认字体 font = ImageFont.load_default(size=30) # 计算文字位置(可选,更精准的居中方式) text_bbox = img_draw.textbbox((0,0), test_text, font=font) text_width = text_bbox[2] - text_bbox[0] text_height = text_bbox[3] - text_bbox[1] x = (img_width - text_width) // 2 y = (img_height - text_height) // 5 img_draw.text((x, y), test_text, fill="yellow", font=font) tk_image = ImageTk.PhotoImage(pil_image) # 保留引用,防止被GC回收 self.tk_image_ref = tk_image return tk_image def update_img_teststep(self): img_name = self.update_tuple[0] teststep_text = f"{self.update_tuple[1]} - number of calls: {self.n_calls}" self.teststep_image = self.open_tk_image(img_name, self.window_width, self.teststep_height, teststep_text) self.TestStep_Label.configure(image=self.teststep_image) self.n_calls += 1 # 循环调用,实现定期更新 self.displ.after(self.update_time, self.update_img_teststep) def simulate_update_tuple(self): # 模拟定时修改更新内容,替代原displ_config中的sleep逻辑 for i in range(1, 3): # 用after延迟执行,避免阻塞主循环 self.displ.after(i * self.update_time * 2, lambda idx=i: self.set_update_tuple(idx)) # 可继续添加更多模拟任务 self.displ.after(6000, self.simulate_update_tuple) def set_update_tuple(self, idx): self.update_tuple = (f"teststep{idx}.jpg", f"this is text #{idx}") self.displ.configure(bg="black") if __name__ == "__main__": displ = Display()
关键修改说明
- 循环更新:在
update_img_teststep末尾添加self.displ.after(self.update_time, self.update_img_teststep),实现每隔1秒自动更新。 - 修复字体设置:使用
ImageFont.truetype指定字体大小,确保文字显示正常。 - 替换
sleep:用after实现定时修改update_tuple,避免阻塞主循环。 - 修正时间单位:将
update_time改为1000毫秒(1秒),符合预期的更新频率。 - 参数修正:给
update_img_teststep去掉不必要的参数,避免调用报错。
内容的提问来源于stack exchange,提问作者user23877086
相关产品推荐
相关产品推荐

