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

如何用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()

问题分析与解决方案

你的代码存在几个关键问题,导致更新失效:

  1. after仅执行一次:当前self.displ.after(self.update_time, self.update_img_teststep)只调用一次更新方法,没有形成循环。需要在update_img_teststep末尾再次调用after,实现定期循环更新。
  2. 时间单位错误:after方法的时间参数单位是毫秒,你设置的self.update_time = 1相当于1毫秒,刷新过快且可能导致主循环阻塞,建议改为1000(1秒)。
  3. time.sleep阻塞主循环:displ_config中的time.sleep会冻结Tkinter主循环,无法处理UI更新,必须改用after来定时修改update_tuple。
  4. 文字大小设置错误:ImageDraw.text没有font_size参数,需要用ImageFont.truetype加载字体并指定大小,否则文字大小不生效。
  5. 参数不匹配: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:02:33