画布中的 Tkinter 窗口没有填充其父级的高度 [英] Tkinter window in canvas doesn't fill its parent in height

查看:29
本文介绍了画布中的 Tkinter 窗口没有填充其父级的高度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I would like to have my scrollbar in the bottom of the frame and my text widgets filling the whole frame above the scrollbar. I found some solution about the width configuration here but when I try to replace width with height, it does not work correctly.

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 如何处理未分配的空间.额外的空间将平均分配给值为 1True 的所有小部件.因为滚动条设置为 1,所以它被赋予了一些额外的空间,导致小部件上方和下方的填充.

Step 1: Remove space above and below the scrollbar

The expand option determines how tkinter handles unallocated space. Extra space will be evenly allocated to all widgets where the value is 1 or True. Because it's set to 1 for the scrollbar, it is given some of the extra space, causing the padding above and below the widget.

您想要的是将所有空间仅分配给画布.通过将滚动条上的 expand 设置为零来执行此操作:

What you want instead is for all of the space to be allocated only to the canvas. Do this by setting expand to zero on the scrollbar:

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

第 2 步:当画布改变大小时调用一个函数

接下来的问题是你希望内框随着canvas改变大小而增长,所以需要绑定canvas的<Configure>事件.

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

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

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

Step 3: let the canvas control the size of the inner frame

You can't just change the size of the inner frame in OnCanvasConfigure, because the default behavior of a frame is to shrink to fit its contents. In this case you want the contents to expand to fit the frame rather than the frame shrink to fit the contents.

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

There are a couple ways you can fix this. You can turn geometry propagation off for the inner frame, which will prevent the inner widgets from changing the size of the frame. Or, you can let the canvas force the size of the frame.

第二种解决方案是最简单的.我们所要做的就是将画布的高度用作框架高度,并将内部文本小部件的宽度总和用作框架宽度.

The second solution is the easiest. All we have to do is use the height of the canvas for the frame height, and the sum of the widths of the inner text widgets for the frame width.

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)

第 4 步:修复滚动条

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

Step 4: fix the scrollbar

There's still one more problem to solve. If you resize the window you'll notice that tkinter will chop off the scrollbar if the window gets too small. You can solve this by removing the ability to resize the window but your users will hate that.

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

A better solution is to cause the text widgets to shrink before the scrollbar is chopped off. You control this by the order in which you call pack.

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

When there isn't enough room to fit all of the widgets, tkinter will start reducing the size of widgets, starting with the last widget added to the window. In your code the scrollbar is the last widget, but if instead you make it the canvas, the scrollbar will remain untouched and the canvas will shrink instead (which in turn causes the frame to shrink, which causes the text widgets to shrink).

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

这篇关于画布中的 Tkinter 窗口没有填充其父级的高度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆