Tkinter Grid布局未将组件放置在正确列位问题
Tkinter Grid布局组件挤在同一列的问题解决
问题描述
尝试使用Tkinter的Grid布局创建可切换双框架的UI,用于用户输入数据。已为各组件设置不同列位,但所有组件均显示在同一列中。
问题代码
import tkinter as tk from tkinter import ttk from matplotlib.figure import Figure from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg class GeneralFrame(ttk.Frame): def __init__(self, *args): super().__init__(*args, padding=10, width=1200, height=600) self.grid_propagate(1) class EntryBox(GeneralFrame): def __init__(self, x_location, y_location, *args): super().__init__(*args) self.entry_box = ttk.Entry(self) self.entry_box.place(x=x_location, y=y_location) print("Placed") def get_data(self): return(self.entry_box.get()) class GliderFrame(GeneralFrame): def __init__(self, *args): super().__init__(*args) self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=1) self.columnconfigure(2, weight=1) ttk.Button(self, text="Add Glider", command=self.add_glider).grid(column=0, row=6) self.polar_coordinate1_label = ttk.Label(text=str("Minimum Sink X Coordinate:")) self.polar_coordinate2_label = ttk.Label(text=str("Minimum Sink Y Coordinate:")) self.polar_coordinate3_label = ttk.Label(text=str("Middle Polar X Coordinate:")) self.polar_coordinate4_label = ttk.Label(text=str("Middle Polar Y Coordinate:")) self.polar_coordinate5_label = ttk.Label(text=str("VNE X Coordinate:")) self.polar_coordinate6_label = ttk.Label(text=str("VNE Y Coordinate:")) self.polar_coordinate1_entry = ttk.Entry(self) self.polar_coordinate2_entry = ttk.Entry(self) self.polar_coordinate3_entry = ttk.Entry(self) self.polar_coordinate4_entry = ttk.Entry(self) self.polar_coordinate5_entry = ttk.Entry(self) self.polar_coordinate6_entry = ttk.Entry(self) def place_widgets(self): self.polar_coordinate1_entry.grid(column=1, row=0, sticky=tk.E) self.polar_coordinate2_entry.grid(column=1, row=1, sticky=tk.E) self.polar_coordinate3_entry.grid(column=1, row=2, sticky=tk.E) self.polar_coordinate4_entry.grid(column=1, row=3, sticky=tk.E) self.polar_coordinate5_entry.grid(column=1, row=4, sticky=tk.E) self.polar_coordinate6_entry.grid(column=1, row=5, sticky=tk.E) self.polar_coordinate1_label.grid(column=0, row=0, sticky=tk.W) self.polar_coordinate2_label.grid(column=0, row=1, sticky=tk.W) self.polar_coordinate3_label.grid(column=0, row=2, sticky=tk.W) self.polar_coordinate4_label.grid(column=0, row=3, sticky=tk.W) self.polar_coordinate5_label.grid(column=0, row=4, sticky=tk.W) self.polar_coordinate6_label.grid(column=0, row=5, sticky=tk.W) def forget_widgets(self): self.polar_coordinate1_entry.grid_forget() self.polar_coordinate2_entry.grid_forget() self.polar_coordinate3_entry.grid_forget() self.polar_coordinate4_entry.grid_forget() self.polar_coordinate5_entry.grid_forget() self.polar_coordinate6_entry.grid_forget() self.polar_coordinate1_label.grid_forget() self.polar_coordinate2_label.grid_forget() self.polar_coordinate3_label.grid_forget() self.polar_coordinate4_label.grid_forget() self.polar_coordinate5_label.grid_forget() self.polar_coordinate6_label.grid_forget() def add_glider(self): polar_coordinates = [[self.polar_coordinate1_entry.get(), self.polar_coordinate2_entry.get()], [self.polar_coordinate3_entry.get(), self.polar_coordinate4_entry.get()], [self.polar_coordinate5_entry.get(), self.polar_coordinate6_entry.get()]] def plot_polar(self, polar): fig = Figure(figsize = (5, 5), dpi = 100) y = [i**2 for i in range(101)] plot1 = fig.add_subplot(111) plot1.plot([0,1,2], [1, 2, 3]) canvas = FigureCanvasTkAgg(fig, self) canvas.show() canvas.get_tk_widget().grid(side=tk.RIGHT) class MapFrame(GeneralFrame): def __init__(self, *args): super().__init__(*args) self.turnpoint1_label = ttk.Label(text=str("Turpoint 1:")) self.turnpoint2_label = ttk.Label(text=str("Turpoint 2:")) self.turnpoint3_label = ttk.Label(text=str("Turpoint 3:")) self.turnpoint4_label = ttk.Label(text=str("Turpoint 4:")) self.turnpoint5_label = ttk.Label(text=str("Turpoint 5:")) self.pilot_mass_label = ttk.Label(text=str("Pilot Weight:")) self.turnpoint1_entry = ttk.Entry(self) self.turnpoint2_entry = ttk.Entry(self) self.turnpoint3_entry = ttk.Entry(self) self.turnpoint4_entry = ttk.Entry(self) self.turnpoint5_entry = ttk.Entry(self) self.pilot_mass_entry = ttk.Entry(self) print("Initiated") def place_widgets(self): self.turnpoint1_entry.grid(column=1, row=0, sticky=tk.E) self.turnpoint2_entry.grid(column=1, row=1, sticky=tk.E) self.turnpoint3_entry.grid(column=1, row=2, sticky=tk.E) self.turnpoint4_entry.grid(column=1, row=3, sticky=tk.E) self.turnpoint5_entry.grid(column=1, row=4, sticky=tk.E) self.pilot_mass_entry.grid(column=1, row=5, sticky=tk.E) self.turnpoint1_label.grid(column=0, row=0, sticky=tk.W) self.turnpoint2_label.grid(column=0, row=1, sticky=tk.W) self.turnpoint3_label.grid(column=0, row=2, sticky=tk.W) self.turnpoint4_label.grid(column=0, row=3, sticky=tk.W) self.turnpoint5_label.grid(column=0, row=4, sticky=tk.W) self.pilot_mass_label.grid(column=0, row=5, sticky=tk.W) def forget_widgets(self): self.turnpoint1_entry.grid_forget() self.turnpoint2_entry.grid_forget() self.turnpoint3_entry.grid_forget() self.turnpoint4_entry.grid_forget() self.turnpoint5_entry.grid_forget() self.pilot_mass_entry.grid_forget() self.turnpoint1_label.grid_forget() self.turnpoint2_label.grid_forget() self.turnpoint3_label.grid_forget() self.turnpoint4_label.grid_forget() self.turnpoint5_label.grid_forget() self.pilot_mass_label.grid_forget() class MainFrame(GeneralFrame): def __init__(self, *args): super().__init__(*args) self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=1) self.columnconfigure(2, weight=1) ttk.Button(self, text="Switch Frame", command=self.change_frames).grid(column=2, row=0) self.MapFrame = MapFrame(self) self.GliderFrame = GliderFrame(self) self.MapFrame.grid() self.MapFrame.place_widgets() self.current_frame = 1 def change_frames(self): print("Changing Frames") if self.current_frame == 1: self.MapFrame.grid_forget() self.MapFrame.forget_widgets() self.GliderFrame.grid(column=0, row=0) self.GliderFrame.place_widgets() self.current_frame = 2 else: self.GliderFrame.grid_forget() self.GliderFrame.forget_widgets() self.MapFrame.grid(column=0, row=0) self.MapFrame.place_widgets() self.current_frame = 1 class App(tk.Tk): def __init__(self): super().__init__() self.geometry("1200x600") self.title("Gliding Task Analysis") self.main_frame = MainFrame(self) self.main_frame.grid(column=0, row=0) App().mainloop()
问题原因
所有Label组件初始化时未指定父容器(即第一个参数self),导致这些标签默认被添加到根窗口,而非对应的GliderFrame或MapFrame中。根窗口的Grid布局和框架内部的Grid布局是独立的,标签和输入框不在同一容器的布局系统里,最终导致所有组件挤在根窗口的同一列。
解决方法
1. 修正Label的父容器
在创建Label时,必须将当前框架self作为第一个参数传入,确保标签属于框架内部的组件:
# 示例:GliderFrame中的Label修正 self.polar_coordinate1_label = ttk.Label(self, text="Minimum Sink X Coordinate:")
2. 优化框架切换逻辑
框架调用grid_forget()后,其内部所有组件会自动隐藏,不需要额外调用forget_widgets(),可以简化change_frames方法。
3. 调整布局间距(可选)
在grid()方法中添加padx和pady参数,提升界面美观度:
# 示例:输入框的Grid布局添加间距 self.polar_coordinate1_entry.grid(column=1, row=0, sticky=tk.E, padx=5, pady=2)
修改后的完整代码
import tkinter as tk from tkinter import ttk from matplotlib.figure import Figure from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg class GeneralFrame(ttk.Frame): def __init__(self, *args): super().__init__(*args, padding=10, width=1200, height=600) self.grid_propagate(1) class EntryBox(GeneralFrame): def __init__(self, x_location, y_location, *args): super().__init__(*args) self.entry_box = ttk.Entry(self) self.entry_box.place(x=x_location, y=y_location) print("Placed") def get_data(self): return self.entry_box.get() class GliderFrame(GeneralFrame): def __init__(self, *args): super().__init__(*args) self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=1) self.columnconfigure(2, weight=1) ttk.Button(self, text="Add Glider", command=self.add_glider).grid(column=0, row=6, pady=10) # 修正:添加self作为父容器 self.polar_coordinate1_label = ttk.Label(self, text="Minimum Sink X Coordinate:") self.polar_coordinate2_label = ttk.Label(self, text="Minimum Sink Y Coordinate:") self.polar_coordinate3_label = ttk.Label(self, text="Middle Polar X Coordinate:") self.polar_coordinate4_label = ttk.Label(self, text="Middle Polar Y Coordinate:") self.polar_coordinate5_label = ttk.Label(self, text="VNE X Coordinate:") self.polar_coordinate6_label = ttk.Label(self, text="VNE Y Coordinate:") self.polar_coordinate1_entry = ttk.Entry(self) self.polar_coordinate2_entry = ttk.Entry(self) self.polar_coordinate3_entry = ttk.Entry(self) self.polar_coordinate4_entry = ttk.Entry(self) self.polar_coordinate5_entry = ttk.Entry(self) self.polar_coordinate6_entry = ttk.Entry(self) # 直接在__init__中布局,无需单独place_widgets方法 self._layout_widgets() def _layout_widgets(self): # 添加padx/pady优化间距 self.polar_coordinate1_entry.grid(column=1, row=0, sticky=tk.E, padx=5, pady=2) self.polar_coordinate2_entry.grid(column=1, row=1, sticky=tk.E, padx=5, pady=2) self.polar_coordinate3_entry.grid(column=1, row=2, sticky=tk.E, padx=5, pady=2) self.polar_coordinate4_entry.grid(column=1, row=3, sticky=tk.E, padx=5, pady=2) self.polar_coordinate5_entry.grid(column=1, row=4, sticky=tk.E, padx=5, pady=2) self.polar_coordinate6_entry.grid(column=1, row=5, sticky=tk.E, padx=5, pady=2) self.polar_coordinate1_label.grid(column=0, row=0, sticky=tk.W, padx=5, pady=2) self.polar_coordinate2_label.grid(column=0, row=1, sticky=tk.W, padx=5, pady=2) self.polar_coordinate3_label.grid(column=0, row=2, sticky=tk.W, padx=5, pady=2) self.polar_coordinate4_label.grid(column=0, row=3, sticky=tk.W, padx=5, pady=2) self.polar_coordinate5_label.grid(column=0, row=4, sticky=tk.W, padx=5, pady=2) self.polar_coordinate6_label.grid(column=0, row=5, sticky=tk.W, padx=5, pady=2) def add_glider(self): polar_coordinates = [ [self.polar_coordinate1_entry.get(), self.polar_coordinate2_entry.get()], [self.polar_coordinate3_entry.get(), self.polar_coordinate4_entry.get()], [self.polar_coordinate5_entry.get(), self.polar_coordinate6_entry.get()] ] print("Polar coordinates saved:", polar_coordinates) def plot_polar(self, polar): fig = Figure(figsize=(5, 5), dpi=100) plot1 = fig.add_subplot(111) plot1.plot([0,1,2], [1, 2, 3]) canvas = FigureCanvasTkAgg(fig, self) canvas.draw() canvas.get_tk_widget().grid(column=2, row=0, rowspan=6, padx=20) class MapFrame(GeneralFrame): def __init__(self, *args): super().__init__(*args) # 修正:添加self作为父容器 self.turnpoint1_label = ttk.Label(self, text="Turnpoint 1:") self.turnpoint2_label = ttk.Label(self, text="Turnpoint 2:") self.turnpoint3_label = ttk.Label(self, text="Turnpoint 3:") self.turnpoint4_label = ttk.Label(self, text="Turnpoint 4:") self.turnpoint5_label = ttk.Label(self, text="Turnpoint 5:") self.pilot_mass_label = ttk.Label(self, text="Pilot Weight:") self.turnpoint1_entry = ttk.Entry(self) self.turnpoint2_entry = ttk.Entry(self) self.turnpoint3_entry = ttk.Entry(self) self.turnpoint4_entry = ttk.Entry(self) self.turnpoint5_entry = ttk.Entry(self) self.pilot_mass_entry = ttk.Entry(self) # 直接在__init__中布局 self._layout_widgets() def _layout_widgets(self): self.turnpoint1_entry.grid(column=1, row=0, sticky=tk.E, padx=5, pady=2) self.turnpoint2_entry.grid(column=1, row=1, sticky=tk.E, padx=5, pady=2) self.turnpoint3_entry.grid(column=1, row=2, sticky=tk.E, padx=5, pady=2) self.turnpoint4_entry.grid(column=
相关产品推荐
相关产品推荐

