Canvas 在带有画布的框架中使用grid.columnconfigure

Canvas 在带有画布的框架中使用grid.columnconfigure,canvas,tkinter,Canvas,Tkinter,我使用下面的代码来创建一个可滚动的框架。现在,我希望网格中的每一列在水平方向上填充整个窗口,也就是当窗口大小改变时 对于这种方法,我总是使用frame.grid\u columnconfigure(col\u num,weight=1)并在放置元素时将sticky=“ew”参数添加到.grid(row,col)命令中 出于某种原因(可能与画布窗口有关),这种方法在以下代码中不起作用 import tkinter as tk # ************************ # Scroll

我使用下面的代码来创建一个可滚动的框架。现在,我希望网格中的每一列在水平方向上填充整个窗口,也就是当窗口大小改变时

对于这种方法,我总是使用frame.grid\u columnconfigure(col\u num,weight=1)并在放置元素时将sticky=“ew”参数添加到.grid(row,col)命令中

出于某种原因(可能与画布窗口有关),这种方法在以下代码中不起作用

import tkinter as tk

# ************************
# Scrollable Frame Class
# ************************


class ScrollFrame(tk.Frame):
    def __init__(self, parent):
        super().__init__(parent)  # create a frame (self)

        # place canvas on self
        self.canvas = tk.Canvas(self, borderwidth=0, background="#ffffff")
        # place a frame on the canvas, this frame will hold the child widgets
        self.viewPort = tk.Frame(self.canvas, background="#ffffff")
        # place a scrollbar on self
        self.vsb = tk.Scrollbar(self, orient="vertical",
                                command=self.canvas.yview)
        # attach scrollbar action to scroll of canvas
        self.canvas.configure(yscrollcommand=self.vsb.set)

        # pack scrollbar to right of self
        self.vsb.pack(side="right", fill="y")
        # pack canvas to left of self and expand to fil
        self.canvas.pack(side="left", fill="both", expand=True)
        self.canvas.create_window((4, 4), window=self.viewPort, anchor="nw",  # add view port frame to canvas
                                  tags="self.viewPort")

        # bind an event whenever the size of the viewPort frame changes.
        self.viewPort.bind("<Configure>", self.onFrameConfigure)

    def onFrameConfigure(self, event):
        '''Reset the scroll region to encompass the inner frame'''
        self.canvas.configure(scrollregion=self.canvas.bbox(
            "all"))  # whenever the size of the frame changes, alter the scroll region respectively.


# ********************************
# Example usage of the above class
# ********************************

class Example(tk.Frame):
    def __init__(self, root):

        tk.Frame.__init__(self, root)
        self.scrollFrame = ScrollFrame(self)  # add a new scrollable frame.

        # try to make the columns filling the entire frame
        self.scrollFrame.viewPort.grid_columnconfigure(0, weight=1)
        self.scrollFrame.viewPort.grid_columnconfigure(1, weight=1)

        # Now add some controls to the scrollframe.
        # NOTE: the child controls are added to the view port (scrollFrame.viewPort, NOT scrollframe itself)
        for row in range(100):
            a = row
            tk.Label(self.scrollFrame.viewPort, text="%s" % row, width=3, borderwidth="1",
                     relief="solid").grid(row=row, column=0, sticky="ew")
            t = "this is the second column for row %s" % row
            tk.Button(self.scrollFrame.viewPort, text=t, command=lambda x=a: self.printMsg(
                "Hello " + str(x))).grid(row=row, column=1, sticky="ew")

        # when packing the scrollframe, we pack scrollFrame itself (NOT the viewPort)
        self.scrollFrame.pack(side="top", fill="both", expand=True)

    def printMsg(self, msg):
        print(msg)


if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(side="top", fill="both", expand=True)
    root.mainloop()
将tkinter作为tk导入
# ************************
#可滚动框架类
# ************************
类ScrollFrame(tk.Frame):
定义初始化(自身,父级):
super().uuu init_uuuuuu(父)#创建一个框架(自)
#把画布放在自己身上
self.canvas=tk.canvas(self,borderwidth=0,background=“#ffffff”)
#在画布上放置一个框架,这个框架将容纳子部件
self.viewPort=tk.Frame(self.canvas,background=“#ffffffff”)
#在self上放置一个滚动条
self.vsb=tk.Scrollbar(self,orient=“vertical”,
command=self.canvas.yview)
#将滚动条动作附加到画布的滚动
self.canvas.configure(yscrollcommand=self.vsb.set)
#将滚动条打包到自身右侧
自包装(side=“right”,fill=“y”)
#将画布包装到self的左侧,并展开到fil
self.canvas.pack(side=“left”,fill=“both”,expand=True)
self.canvas.create_window((4,4),window=self.viewPort,anchor=“nw”,#将视图端口框架添加到画布
tags=“self.viewPort”)
#每当视口帧的大小更改时,都会绑定事件。
self.viewPort.bind(“,self.onFrameConfigure)
def onFrameConfigure(自我,事件):
''重置滚动区域以包含内部框架''
self.canvas.configure(scrollregion=self.canvas.bbox(
“全部”)#每当帧大小改变时,分别改变滚动区域。
# ********************************
#上述类的示例用法
# ********************************
类示例(tk.Frame):
定义初始化(自,根):
tk.Frame.\uuuu init\uuuu(self,root)
self.scrollFrame=scrollFrame(self)#添加新的可滚动框架。
#尝试使列填充整个框架
self.scrollFrame.viewPort.grid\u columnconfigure(0,权重=1)
self.scrollFrame.viewPort.grid\u columnconfigure(1,权重=1)
#现在向滚动框添加一些控件。
#注意:子控件添加到视图端口(scrollFrame.viewPort,而不是scrollFrame本身)
对于范围(100)中的行:
a=行
标签(self.scrollFrame.viewPort,text=“%s”%row,width=3,borderwidth=“1”,
relief=“solid”).grid(行=行,列=0,sticky=“ew”)
t=“这是第%s行“%row”的第二列
按钮(self.scrollFrame.viewPort,text=t,command=lambda x=a:self.printMsg(
“Hello”+str(x)).grid(row=row,column=1,sticky=“ew”)
#打包scrollframe时,我们打包scrollframe本身(而不是视口)
self.scrollFrame.pack(side=“top”,fill=“both”,expand=True)
def printMsg(自我,msg):
打印(msg)
如果名称=“\uuuuu main\uuuuuuuu”:
root=tk.tk()
示例(root).pack(side=“top”,fill=“both”,expand=True)
root.mainloop()

非常感谢您的建议

问题不在于列的扩展和收缩,而是它们所在的框架没有增长或收缩

要解决这个问题,您需要绑定到画布的
事件。当它改变大小时,您可以强制内部框架与画布的宽度相同

首先,建立约束机制:

self.canvas.bind("<Configure>", self.onCanvasConfigure)
def onCanvasConfigure(self, event):
    self.canvas.itemconfigure("self.viewPort", width=event.width)