为什么Frame的自然高度没有立即更新?

2 投票
1 回答
635 浏览
提问于 2025-04-18 14:52

我正在写一个小工具,用来显示一些文本行(通过一个Label放在一个Frame里),当文本的高度超过包含它的Frame的高度时,我需要调整字体大小。

为此,我在文本更新后,会查询LabelFrame的高度,使用.winfo_reqheight()这个方法,想要把字体大小调小,然后重新写入文本,重复这个过程,直到文本适合为止(如果有更好的主意,我非常欢迎)。

总之,我写了一个测试脚本来实现这个功能,但我发现更新文本后,Frame的高度和Label的高度比起来差了一点。

具体来说:这段代码

import Tkinter as tk

class App():
    def __init__(self):
        self.root = tk.Tk()
        self.root.geometry("200x200")
        self.f = tk.Frame(self.root)
        self.f.pack(expand=True, fill=tk.BOTH)
        self.l = tk.Label(self.f)
        self.l.pack(expand=True, fill=tk.BOTH)
        self.root.bind("q", func=self.addline)
        self.counter = 0

    def addline(self, event):
        mylist = list()
        self.counter += 1
        for _ in range(self.counter):
            mylist.append("hello")
        message = '\n'.join(mylist)
        self.l.configure(text=message, font=('Arial', 30))
        print("frame: {0} label {1}".format(self.f.winfo_reqheight(), self.l.winfo_reqheight()))

App().root.mainloop()

在按了三次q后显示的效果是

在这里输入图片描述

并且输出是

frame: 21 label 51
frame: 51 label 96
frame: 96 label 141

你看Frame的大小差了一点吗?尽管这两个小部件是同时查询的,为什么会出现这种情况呢?

1 个回答

1

在事件处理程序返回之前,里面所做的更改是不会更新的。

不过,你可以通过使用 update_idletasks 来强制更新:

self.l.configure(text=message, font=('Arial', 30))
self.l.update_idletasks()

在这里输入图片描述

更新

winfo_height() 的文档也提到了 update_idletasks

获取这个小部件的高度,单位是像素。注意,如果这个窗口没有被几何管理器管理,这个方法会返回1。 要获取真实的值,你可能需要先调用 update_idletasks。你也可以使用 winfo_reqheight 来获取小部件请求的高度(也就是根据小部件内容定义的“自然”大小)。

撰写回答