Tkinter Canvas 覆盖其他小部件
Tkinter Canvas Cover Other Widgets
我正在尝试创建一个具有简单布局的应用程序,该应用程序将页眉、canvas 和页脚垂直对齐。
我想出了以下代码:
import tkinter as tk
from tkinter import ttk
class CanvasView(tk.Canvas):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
self.height = self.winfo_reqheight()
self.width = self.winfo_reqwidth()
self.bind("<Configure>", self.on_resize)
def on_resize(self, event):
self.height = event.height
self.width = event.width
self.config(width=self.width, height=self.height)
# print(f"new size={self.width}x{self.height}")
class Viewer:
def run(self):
self.make_main_window()
self.make_header()
# self.make_canvas() # * uncomment to see bug
self.make_footer()
self.root.mainloop()
def make_main_window(self):
# main window
root = tk.Tk()
root.title = "My Tk Layout Test"
root.geometry("640x480")
root.update() # force update to set minsize
root.minsize(root.winfo_width(), root.winfo_height())
self.root = root
def make_header(self):
header_frm = ttk.Frame(master=self.root)
header_frm.pack(side=tk.TOP, fill=tk.X)
lbl = tk.Label(header_frm, text="My Viewer Header Text")
lbl.grid(row=0, column=0, sticky="nsew")
# config uniform column sizes
num_col, _ = header_frm.grid_size()
for i in range(num_col):
header_frm.grid_columnconfigure(i, weight=1, uniform="tag")
self.header_frm = header_frm
def make_canvas(self):
canvas_frm = ttk.Frame(master=self.root)
canvas_frm.pack(side=tk.TOP)
canvas = CanvasView(canvas_frm, bg="red")
canvas.pack()
self.canvas_frm = canvas_frm
def make_footer(self):
btn_frm = ttk.Frame(master=self.root)
btn_frm.pack(side=tk.BOTTOM, fill=tk.X)
btn_list = [
tk.Label(btn_frm, text=""), # spacer
tk.Label(btn_frm, text=""), # spacer
tk.Button(btn_frm, text="Control 1"),
tk.Button(btn_frm, text="Control 2"),
tk.Button(btn_frm, text="Control 3"),
tk.Button(btn_frm, text="Control 4"),
tk.Button(btn_frm, text="Control 5"),
tk.Label(btn_frm, text=""), # spacer
tk.Label(btn_frm, text=""), # spacer
]
for i, btn in enumerate(btn_list):
btn.configure(height=2) # height in text units
btn.grid(row=0, column=i, sticky="nsew")
# config uniform column sizes
num_col, _ = btn_frm.grid_size()
for i in range(num_col):
btn_frm.grid_columnconfigure(i, weight=1, uniform="tag")
self.footer_frm = btn_frm
if __name__ == "__main__":
viewer = Viewer()
viewer.run()
没有调用 self.make_canvas()
,我得到以下屏幕,它很好地显示了页眉和页脚:
但是当调用 self.make_canvas()
时,我得到以下信息:
如何修复它,使红色 canvas 不会 运行 在我的页脚上?
canvas 并未 覆盖 其他小部件,它迫使它们脱离 window。您强制 window 为特定大小,然后您添加的小部件总体上太高而无法容纳,因此 tkinter 必须缩小某些东西以适合 window 中的所有小部件。
调用 pack
的顺序很重要。当小部件不适合时,打包器将开始减小小部件的大小以适合,从添加到给定 space 的最后一个小部件开始。在这种情况下,页脚是最后添加的小部件,因此 tkinter 会缩小它以适合它。最终,它将缩小到零大小。
一个简单的解决方案是在添加 canvas 之前添加 header 和页脚。这样,如果小部件不适合,那么 canvas 将是缩小的那个。由于它是最大的小部件并且可以滚动,因此这是允许缩小的逻辑小部件,因此应按时间顺序最后打包。
来自官方文档,在标题为 The Packer Algorithm 的部分中:
If the cavity should become too small to meet the needs of a content then the content will be given whatever space is left in the cavity. If the cavity shrinks to zero size, then all remaining content on the packing list will be unmapped from the screen until the container window becomes large enough to hold them again.
我正在尝试创建一个具有简单布局的应用程序,该应用程序将页眉、canvas 和页脚垂直对齐。
我想出了以下代码:
import tkinter as tk
from tkinter import ttk
class CanvasView(tk.Canvas):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
self.height = self.winfo_reqheight()
self.width = self.winfo_reqwidth()
self.bind("<Configure>", self.on_resize)
def on_resize(self, event):
self.height = event.height
self.width = event.width
self.config(width=self.width, height=self.height)
# print(f"new size={self.width}x{self.height}")
class Viewer:
def run(self):
self.make_main_window()
self.make_header()
# self.make_canvas() # * uncomment to see bug
self.make_footer()
self.root.mainloop()
def make_main_window(self):
# main window
root = tk.Tk()
root.title = "My Tk Layout Test"
root.geometry("640x480")
root.update() # force update to set minsize
root.minsize(root.winfo_width(), root.winfo_height())
self.root = root
def make_header(self):
header_frm = ttk.Frame(master=self.root)
header_frm.pack(side=tk.TOP, fill=tk.X)
lbl = tk.Label(header_frm, text="My Viewer Header Text")
lbl.grid(row=0, column=0, sticky="nsew")
# config uniform column sizes
num_col, _ = header_frm.grid_size()
for i in range(num_col):
header_frm.grid_columnconfigure(i, weight=1, uniform="tag")
self.header_frm = header_frm
def make_canvas(self):
canvas_frm = ttk.Frame(master=self.root)
canvas_frm.pack(side=tk.TOP)
canvas = CanvasView(canvas_frm, bg="red")
canvas.pack()
self.canvas_frm = canvas_frm
def make_footer(self):
btn_frm = ttk.Frame(master=self.root)
btn_frm.pack(side=tk.BOTTOM, fill=tk.X)
btn_list = [
tk.Label(btn_frm, text=""), # spacer
tk.Label(btn_frm, text=""), # spacer
tk.Button(btn_frm, text="Control 1"),
tk.Button(btn_frm, text="Control 2"),
tk.Button(btn_frm, text="Control 3"),
tk.Button(btn_frm, text="Control 4"),
tk.Button(btn_frm, text="Control 5"),
tk.Label(btn_frm, text=""), # spacer
tk.Label(btn_frm, text=""), # spacer
]
for i, btn in enumerate(btn_list):
btn.configure(height=2) # height in text units
btn.grid(row=0, column=i, sticky="nsew")
# config uniform column sizes
num_col, _ = btn_frm.grid_size()
for i in range(num_col):
btn_frm.grid_columnconfigure(i, weight=1, uniform="tag")
self.footer_frm = btn_frm
if __name__ == "__main__":
viewer = Viewer()
viewer.run()
没有调用 self.make_canvas()
,我得到以下屏幕,它很好地显示了页眉和页脚:
但是当调用 self.make_canvas()
时,我得到以下信息:
如何修复它,使红色 canvas 不会 运行 在我的页脚上?
canvas 并未 覆盖 其他小部件,它迫使它们脱离 window。您强制 window 为特定大小,然后您添加的小部件总体上太高而无法容纳,因此 tkinter 必须缩小某些东西以适合 window 中的所有小部件。
调用 pack
的顺序很重要。当小部件不适合时,打包器将开始减小小部件的大小以适合,从添加到给定 space 的最后一个小部件开始。在这种情况下,页脚是最后添加的小部件,因此 tkinter 会缩小它以适合它。最终,它将缩小到零大小。
一个简单的解决方案是在添加 canvas 之前添加 header 和页脚。这样,如果小部件不适合,那么 canvas 将是缩小的那个。由于它是最大的小部件并且可以滚动,因此这是允许缩小的逻辑小部件,因此应按时间顺序最后打包。
来自官方文档,在标题为 The Packer Algorithm 的部分中:
If the cavity should become too small to meet the needs of a content then the content will be given whatever space is left in the cavity. If the cavity shrinks to zero size, then all remaining content on the packing list will be unmapped from the screen until the container window becomes large enough to hold them again.