Tkinter用类与tkraise()切换Frame时如何固定为600×400(偏好Grid)
问题根源
Tkinter Frame默认开启几何传播机制,会自动根据内部子组件的总大小调整自身尺寸,哪怕初始化时指定了width/height参数,只要不关闭该机制,Frame就会被内容撑开。另外原代码中创建的container容器没有被用作页面Frame的父组件,属于冗余代码,没有起到约束尺寸的作用。
修复方案
全程遵循Grid布局要求,无需使用Pack,改动点如下:
- 在每个页面Frame的初始化逻辑中,添加
self.grid_propagate(False),强制关闭几何传播,让Frame保持固定尺寸。 - 移除无用的
container代码,主窗口和页面Frame的布局统一使用Grid,无需使用place。 - 移除模糊导入(
from tkinter import *、from tkinter.ttk import *),统一用tk.xxx显式调用组件,避免tk和ttk组件的尺寸计算冲突。
修复后代码
import tkinter as tk from tkinter import font as tkfont from PIL import ImageTk, Image class InterimMain(tk.Tk): def __init__(self, *args, **kwargs): tk.Tk.__init__(self, *args, **kwargs) # 主窗口尺寸与居中配置 window_width = 800 window_height = 600 position_right = int(self.winfo_screenwidth()/2 - window_width/2) position_down = int(self.winfo_screenheight()/2 - window_height/2) self.geometry(f"{window_width}x{window_height}+{position_right}+{position_down}") # 主窗口Grid配置,让页面Frame居中 self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1) self.frames = {} for F in (WelcomeScreen, Login): page_name = F.__name__ frame = F(parent=self, controller=self) self.frames[page_name] = frame # Grid布局放置堆叠的页面Frame frame.grid(row=0, column=0, sticky="nsew") self.show_frame("WelcomeScreen") def show_frame(self, page_name): '''Show a frame for the given page name''' frame = self.frames[page_name] frame.tkraise() class WelcomeScreen(tk.Frame): def __init__(self, parent, controller): # 初始化固定尺寸的Frame tk.Frame.__init__(self, parent, width=600, height=400) # 关闭几何传播,禁止被内部内容撑开 self.grid_propagate(False) tk.Label(self,text="WELCOME TO THE INTRIM REPORT",font=("Arial Bold",16)).grid(row=0, pady=20) load = Image.open("logo2.jpg") render = ImageTk.PhotoImage(load) img = tk.Label(self, image=render) img.image = render # 保留图片引用,避免被GC回收 img.grid(row=1) tk.Label(self,text="Press the button to proceed",font=("Arial Bold",10)).grid(row=2, padx=5, pady=10) tk.Button(self,text="Sign In",font=("Arial Bold",16),command=lambda: controller.show_frame("Login")).grid(row=3, padx=20, pady=20) class Login(tk.Frame): def __init__(self, parent, controller): tk.Frame.__init__(self, parent, width=600, height=400) self.grid_propagate(False) self.config(background="blue") tk.Label(self,text="LOGIN SCREEN",font=("Arial Bold",16)).grid(row=0,column=0,pady=10,columnspan=3) tk.Label(self,text="Username",font=("Arial",12)).grid(row=1,column=0,sticky='w') tk.Label(self,text="Password",font=("Arial",12)).grid(row=2,column=0,sticky='w') user = tk.Entry(self) pwd = tk.Entry(self) user.grid(row=1,column=1,pady=5,columnspan=2,sticky='we') pwd.grid(row=2,column=1,pady=5,columnspan=2,sticky='we') # 补充原代码缺失的checkLogin占位逻辑 def checkLogin(u, p): pass tk.Button(self,text="LOGIN",command=lambda: checkLogin(user.get(), pwd.get())).grid(row=3,column=2,columnspan=3,sticky='e') if __name__ == "__main__": app = InterimMain() app.mainloop()
注意事项
grid_propagate(False)是核心逻辑,启用后Frame会严格保持你设置的600×400尺寸,不会被内部子组件撑开。- 主窗口的
grid_rowconfigure/grid_columnconfigure配置了weight=1,是为了让堆叠的页面Frame自动居中,完全没有使用Pack布局。 - 必须保留图片的引用赋值(
img.image = render),否则Tkinter的垃圾回收机制会自动销毁图片资源,导致图片无法显示。
内容的提问来源于stack exchange,提问作者Mixstah
相关产品推荐
相关产品推荐

