Skip to main content
 首页 » 编程设计

python之Canvas 中的 Tkinter 窗口不会填充其父级的高度

2025年05月04日15傻小

我想让我的滚动条位于框架的底部,我的文本小部件填充滚动条上方的整个框架。我找到了一些关于宽度配置的解决方案 here但是当我尝试用高度替换宽度时,它无法正常工作。

from tkinter import * 
from tkinter import ttk 
 
class MainView(Frame): 
 
    def FrameHeight(self, event): 
        canvas_height = event.height 
        self.canvas.itemconfig(self.canvas_frame, height=canvas_height) 
 
    def OnFrameConfigure(self, event): 
        self.canvas.config(scrollregion=self.canvas.bbox("all")) 
 
    def __init__(self, *args, **kwargs): 
        Frame.__init__(self, *args, **kwargs) 
        self.grid_columnconfigure(0, weight=1) 
        self.grid_rowconfigure(0, weight=1) 
 
        sensorsFrame = Frame(self) 
        sensorsFrame.grid(row=0, sticky="nsew") 
        sensorsFrame.grid_columnconfigure(0, weight=1) 
        sensorsFrame.grid_rowconfigure(0, weight=1) 
 
        self.canvas = Canvas(sensorsFrame) 
        self.sensorsStatsFrame = Frame(self.canvas) 
        self.canvas.grid_rowconfigure(0, weight=1) 
        self.sensorsStatsFrame.grid_rowconfigure(0, weight=1) 
 
        myscrollbar = Scrollbar(sensorsFrame,orient=HORIZONTAL,command=self.canvas.xview) 
        self.canvas.configure(xscrollcommand=myscrollbar.set) 
        self.canvas.pack(fill=BOTH, expand=1) 
        myscrollbar.pack(fill=X, expand=1) 
 
        test0 = Text(self.sensorsStatsFrame, state=DISABLED) 
        test1 = Text(self.sensorsStatsFrame, width=150) 
        test0.grid(column=0, row=0, sticky="nsew") 
        test1.grid(column=1, row=0, sticky="nsew") 
 
        self.canvas_frame = self.canvas.create_window((0,0),window=self.sensorsStatsFrame,anchor='nw') 
        self.sensorsStatsFrame.bind("<Configure>", self.OnFrameConfigure) 
 
        #When I try to use what i found 
        #self.canvas.bind('<Configure>', self.FrameHeight) 
 
if __name__ == "__main__": 
    root = Tk() 
    main = MainView(root) 
    main.pack(fill="both", expand=1) 
    root.wm_geometry("1100x500") 
    root.wm_title("MongoDB Timed Sample Generator") 
    root.mainloop() 

请您参考如下方法:

第 1 步:删除滚动条上方和下方的空间

expand选项确定 tkinter 如何处理未分配的空间。额外空间将平均分配给值为1的所有小部件或 True .因为它设置为 1对于滚动条,它被赋予了一些额外的空间,导致小部件上方和下方的填充。

您想要的是将所有空间仅分配给 Canvas 。通过设置 expand 来做到这一点在滚动条上归零:

myscrollbar.pack(fill=X, expand=0) 

第二步: Canvas 尺寸变化时调用函数

下一个问题是你希望内框在 Canvas 改变大小时增长,所以你需要绑定(bind)到<Configure>。 Canvas 的事件。

def OnCanvasConfigure(self, event): 
    <code to set the size of the inner frame> 
... 
self.canvas.bind("<Configure>", self.OnCanvasConfigure) 

第三步:让 Canvas 控制内框的大小

您不能只更改 OnCanvasConfigure 中内框的大小,因为框架的默认行为是缩小以适合其内容。在这种情况下,您希望内容扩展以适合框架而不是框架缩小以适合内容。

有几种方法可以解决这个问题。您可以为内部框架关闭几何传播,这将防止内部小部件更改框架的大小。或者,您可以让 Canvas 强制调整框架的大小。

第二种解决方案是最简单的。我们所要做的就是使用 Canvas 的高度作为框架高度,并将内部文本小部件的宽度之和作为框架宽度。

def OnCanvasConfigure(self, event): 
    width = 0 
    for child in self.sensorsStatsFrame.grid_slaves(): 
        width += child.winfo_reqwidth() 
 
    self.canvas.itemconfigure(self.canvas_frame, width=width, height=event.height) 

第四步:修复滚动条

还有一个问题要解决。如果调整窗口大小,您会注意到如果窗口太小,tkinter 会切断滚动条。您可以通过删除调整窗口大小的功能来解决此问题,但您的用户会讨厌这样。

更好的解决方案是在滚动条被截断之前使文本小部件收缩。您可以通过调用 pack 的顺序来控制它.

当没有足够的空间容纳所有小部件时,tkinter 将开始减小小部件的大小,从添加到窗口的最后一个小部件开始。在您的代码中,滚动条是最后一个小部件,但是如果您将其设为 Canvas ,则滚动条将保持不变并且 Canvas 将缩小(这反过来会导致框架缩小,从而导致文本小部件缩小)。

myscrollbar.pack(side="bottom", fill=X, expand=0) 
self.canvas.pack(fill=BOTH, expand=1)