Python Tkinter仅root为父组件时控件显示 self为父时不显示原因
问题根本原因
核心是作为父容器的MainGUI(也就是代码里的self)默认尺寸为11像素,其内部用place布局的子控件全部超出父容器可视边界被裁切,只有直接绑定到root的控件因为顶层窗口有固定300400尺寸才能正常显示,具体逻辑如下:
place布局不会参与父容器的尺寸计算:和pack/grid布局会自动通知父容器根据子控件大小调整自身尺寸不同,place是绝对定位布局,父容器完全感知不到内部用place放置的控件大小,你没有给MainGUI设置固定尺寸、也没有配置它的布局填充规则,它初始化后默认缩成1个像素大小,相当于窗口里一个看不见的点,里面放的图片Label自然也跟着落在可视区域外。- 渲染层级跟随父容器:Tkinter的控件显示范围完全受父容器边界限制,父容器本身只有1像素大,就算子控件设置了300*400的尺寸,超出父容器的部分也会被直接裁切不显示。你把哪个控件的父级设为有固定尺寸的
root,哪个控件就能在顶层窗口的坐标体系里正常渲染,父级设为self的控件就因为父容器太小被藏起来,才会出现互换父级就翻转显示异常的现象。 - 历史项目可正常运行的原因是漏了父容器的布局配置:历史代码里要么给
MainGUI设置了固定尺寸,要么调用pack时加了fill=tk.BOTH, expand=True参数让它撑满整个root窗口,要么内部有子控件用pack/grid布局触发了父容器自适应,不存在两边代码完全一致的情况。
修复方案
- 调整
MainGUI实例的布局参数,让它撑满整个root窗口,获得足够的显示尺寸 - 修正类内部属性和方法重名的隐患,统一控件父级,不要在类内部直接跨层级引用全局的
root作为控件父容器
修复后的可运行代码如下:
import tkinter as tk import PIL.Image import PIL.ImageTk import sys, os #GUI Class class MainGUI(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self,parent) self.parent=parent self.setup_widgets() # 原方法名test和后续属性重名,改名避免方法覆盖 def setup_widgets(self): self.bImage = PIL.ImageTk.PhotoImage(PIL.Image.open("Background.png")) self.bLabel = tk.Label(self, image=self.bImage) self.bLabel.image=self.bImage self.bLabel.place(x=0,y=0,width=300,height=400) # 控件父级统一用self,属性名不与方法重名 self.test_frame = tk.Frame(self, bg="red") self.test_frame.place(x=10,y=10,width=50,height=50) if __name__ == "__main__": root=tk.Tk() root.title("Buddy Swap") root.geometry("300x400") root.resizable(0,0) root.iconbitmap(os.path.dirname(sys.argv[0])+"\\Icon.ico") # 补上fill和expand参数,让MainGUI撑满整个窗口 MainGUI(root).pack(fill=tk.BOTH, expand=True) root.mainloop()
内容的提问来源于stack exchange,提问作者LostSilverCoin
相关产品推荐
相关产品推荐

