Tkinter中Icon与MenuBar组合导致窗口Geometry异常变更问题
Tkinter同时设置图标和菜单栏导致Geometry值异常的解决方法
问题场景
我想要把Tkinter窗口的geometry值保存到配置文件,但发现同时设置窗口图标和菜单栏时,获取的geometry值会异常:
- 代码里初始设置窗口为
800x500+200+200,但关闭窗口时打印出来的却是800x480+200+200 - 保存这个异常值重新加载后,窗口每次启动都会变小
- 只要移除菜单栏或者图标其中一个,关闭时就能正常获取到高度500,仅两者同时存在才会触发问题
复现代码
import tkinter as tk class NewGUI(): def __init__(self): self.root = tk.Tk() self.root.geometry('800x500+200+200') self.root.protocol("WM_DELETE_WINDOW", self.on_close) self.root.iconbitmap('C:\Program Files\Python39\DLLs\pyc.ico') menubar = tk.Menu(self.root) self.root.config(menu=menubar) menubar.add_command(label="Settings") self.root.mainloop() def on_close(self): print(self.root.geometry()) self.root.destroy() if __name__ == '__main__': new = NewGUI()
问题原因
这是Windows平台下Tkinter的一个已知bug:当同时设置窗口图标和菜单栏后,geometry()方法错误地返回了窗口客户区的高度(即去掉菜单栏后的内部高度),而非整个窗口的实际高度,菜单栏的高度(通常20px)被无故扣除了。
解决办法
方法1:使用窗口信息方法获取真实尺寸
用winfo_width()、winfo_height()、winfo_x()、winfo_y()分别获取窗口的真实宽、高和位置,再拼接成正确的geometry字符串:
def on_close(self): width = self.root.winfo_width() height = self.root.winfo_height() x = self.root.winfo_x() y = self.root.winfo_y() correct_geometry = f"{width}x{height}+{x}+{y}" print(correct_geometry) self.root.destroy()
方法2:强制更新窗口布局后再获取
在读取geometry前调用update_idletasks(),让窗口完成所有布局渲染,确保获取到正确的数值:
def on_close(self): self.root.update_idletasks() print(self.root.geometry()) self.root.destroy()
方法3:调整图标和菜单栏的设置顺序
先设置菜单栏再设置图标(或反过来),部分场景下可以规避这个bug:
def __init__(self): self.root = tk.Tk() self.root.geometry('800x500+200+200') self.root.protocol("WM_DELETE_WINDOW", self.on_close) # 先设置菜单栏,再设置图标 menubar = tk.Menu(self.root) self.root.config(menu=menubar) menubar.add_command(label="Settings") self.root.iconbitmap(r'C:\Program Files\Python39\DLLs\pyc.ico') self.root.mainloop()
内容的提问来源于stack exchange,提问作者NablaDelta
相关产品推荐
相关产品推荐

