在 Tkinter
中,Frame
是一个容器部件,用于组织和管理布局。如果多个 Frame
出现在同一个父容器中并且看起来相互覆盖,通常与布局管理器的使用方式或控件的创建顺序有关。
以下是几个常见的原因和解决方案,帮助你了解为什么多个 Frame
会相互覆盖:
问题背景
我在使用 Tkinter 构建 Python GUI 时遇到一个问题。我的想法是在根 Frame 中构建多个 Frame。我可以让 2 个 Frame 显示出来,但第 3 个 Frame 会覆盖第 2 个 Frame。我尝试将 pack() 和 grid() 都用作根 Frame 中的布局管理器。
我希望有一个“Stuff At The Top”Frame 和一个“Stuff At The Bottom”Frame,中间有 1 个 Cat1 Frame 和 1 到 8 个 Cat2 Frames。该 GUI 需要能够随着应用程序发现它控制的 Cat2 控件的数量而动态地重新构建。
我还遇到另一个小问题。自从我引入了 Cat2Frame 类并将 tkFont 变量移至全局作用域后,我的 12 号字体仍然只有 9 号。
下面是我经过清理的代码片段。(尚未涉及底部 Frame。)
def anchor(widget, rows=0, cols=0):
"""Takes care of anchoring/stretching widgets via grid 'sticky'"""
for r in range(rows):
widget.rowconfigure(r, weight=1)
for c in range(cols):
widget.columnconfigure(c, weight=1)
font_ = None
bold_ = None
bold_12 = None
class TkinterGui():
"""Tkinter implementation of the GUI"""
def __init__(self):
"""Create the Tkinter GUI"""
self._top_level = None
self._top_row = None
self._buildGui(_TITLE)
def _buildGui(self, title):
"""Build the Tkinter GUI"""
self._top_level = Tkinter.Tk()
font_ = tkFont.Font(family='FreeSans', size=9)
bold_ = tkFont.Font(family='FreeSans', size=9, weight='bold')
bold_12 = tkFont.Font(family='FreeSans', size=12, weight='bold')
anchor(self._top_level, 4, 1)
self._top_row = 0
self._buildTop()
self._top_row = 1
self._buildCat1()
t1 = Cat2Frame(self._top_level, "Cat2 1")
self._top_row = 2
t1.place_frame(self._top_row)
t5 = Cat2Frame(self._top_level, "Cat2 5")
self._top_row = 3
t5.place_frame(self._top_row)
self._top_level.title(title)
def _buildTop(self):
"""Private method to build the Top frame of the GUI."""
top_frame = Tkinter.Frame(self._top_level, name='top_frame')
anchor(top_frame, 1, 3)
top_frame.columnconfigure(0, weight=2)
top_frame.columnconfigure(1, weight=5)
col1_label = Tkinter.Label(top_frame
, name='col1_label'
, text="Col1"
, font=bold_12
, width=20
).grid(row=0
, column=0
, sticky=N+E+W+S
)
col2_label = Tkinter.Label(top_frame
, name='col2_label'
, text="Col2"
, font=bold_12
, width=40
).grid(row=0
, column=1
, sticky=N+E+W+S
)
top_button = Tkinter.Button(top_frame
, name='top_button'
, text='Top Button'
, font=bold_
).grid(row=0
, column=2
, sticky=E
)
top_frame.grid(row=self._top_row, column=0, sticky=N+W)
def _buildCat1(self):
"""Private method to build the Cat1 frame of the GUI"""
cat1_frame = Tkinter.Frame(self._top_level, name='cat1_frame')
anchor(cat1_frame, 3, 3)
cur_row = 0
cat1_frame.columnconfigure(2, weight=6)
Tkinter.Label(cat1_frame
, name='cat1_label'
, text='Cat1'
, font=bold_
).grid(row=cur_row, column=0, sticky=N+E+W+S)
cat1_size = Tkinter.Text(cat1_frame
, name='cat1_size'
, state=DISABLED
, font=font_
, height=1
, width=10
).grid(row=cur_row
, column=1
, sticky=E
)
cat1_status = Tkinter.Text(cat1_frame
, name='cat1_status'
, state=DISABLED
, font=font_
, height=3
, width=72
).grid(row=cur_row
, column=2
, rowspan=3
, sticky=N+E+W+S
)
cur_row += 1
cat1_model = Tkinter.Text(cat1_frame
, name='cat1_model'
, state=DISABLED
, font=font_
, height=1
, width=30
).grid(row=cur_row
, column=0
, columnspan=2
, sticky=N+W
)
cur_row += 1
cat1_serial = Tkinter.Text(cat1_frame
, name='cat1_serial'
, state=DISABLED
, font=font_
, height=1
, width=30
).grid(row=cur_row
, column=0
, columnspan=2
, sticky=N+W
)
cat1_frame.grid(row=self._top_row, column=0, sticky=N+W)
class Cat2Frame():
"""Class encapsulation for a Cat2 Frame in the GUI"""
def __init__(self, parent, t_label):
"""Initialize a Cat2 Frame in the GUI"""
self._frame = Tkinter.Frame(parent, name='cat2_frame')
anchor(self._frame, 3, 4)
self.cur_row = 0
self._frame.columnconfigure(2, weight=5)
self._label = Tkinter.Label(self._frame
, name='cat2_label'
, text=t_label
, font=bold_
)
self._size = Tkinter.Text(self._frame
, name='cat2_size'
, state=DISABLED
, font=font_
, height=1
, width=10
)
self._status = Tkinter.Text(self._frame
, name='cat2_status'
, state=DISABLED
, font=font_
, height=3
, width=60
)
self._control = Tkinter.IntVar()
self._enabled = Tkinter.Radiobutton(self._frame
, name='cat2_enabled'
, variable=self._control
, text='Enabled'
, font=bold_
, value=1
)
self._model = Tkinter.Text(self._frame
, name='cat2_model'
, state=DISABLED
, font=font_
, height=1
, width=30
)
self._disabled = Tkinter.Radiobutton(self._frame
, name='cat2_disabled'
, variable=self._control
, text='Disabled'
, font=bold_
, value=0
)
self._serial = Tkinter.Text(self._frame
, name='cat2_serial'
, state=DISABLED
, font=font_
, height=1
, width=3
当多个 Frame
在 Tkinter
中相互覆盖时,问题通常与布局管理器的使用有关。要避免这种情况,可以:
- 确保使用布局管理器时,明确指定位置 (
pack(side=...)
或grid(row=..., column=...)
)。 - 不要在同一个容器中混用
pack()
和grid()
。 - 使用
place()
布局时,注意坐标设置,确保不同部件不在同一位置。 - 如果
Frame
没有子部件,确保为它们设置合适的宽度和高度。
通过合理的布局管理,可以确保 Frame
之间不会发生相互覆盖的问题。如果有具体的代码,我可以帮助进一步调试。