Python 画布内部的tkinter框架未扩展以填充区域

Python 画布内部的tkinter框架未扩展以填充区域,python,tkinter,Python,Tkinter,我有一个可滚动的frame类,是从我找到的一些代码中借来的,我很难调整它来满足我的需要。它是由.pack()管理的,但我需要使用.grid(),所以我只需将一个框架(self.region)打包到其中,这样我就可以对其中的小部件进行网格化。然而,这个框架内的小部件不会扩展到容器的边缘,我不知道为什么。有许多问题与我的类似,但似乎没有一个解决方案能起到作用。我尝试使用.grid\u columnconfigure、.columnconfigure()和.bind(“Configure”)都没有用。

我有一个可滚动的frame类,是从我找到的一些代码中借来的,我很难调整它来满足我的需要。它是由.pack()管理的,但我需要使用.grid(),所以我只需将一个框架(
self.region
)打包到其中,这样我就可以对其中的小部件进行网格化。然而,这个框架内的小部件不会扩展到容器的边缘,我不知道为什么。有许多问题与我的类似,但似乎没有一个解决方案能起到作用。我尝试使用
.grid\u columnconfigure
.columnconfigure()
.bind(“Configure”)
都没有用。有没有人建议让我的可滚动区域中的小部件向东和向西扩展以填充窗口

import tkinter as tk
from tkinter import ttk

class ScrollableFrame(ttk.Frame):
    """taken from https://blog.tecladocode.com/tkinter-scrollable-frames/ and modified to
    allow for the use of grid inside self.region
    Class that allows for the creation of a frame that is scrollable"""
    def __init__(self, container, *args, **kwargs):
        super().__init__(container, *args, **kwargs)
        canvas = tk.Canvas(self)
        scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
        self.scrollable_frame = ttk.Frame(canvas)
        canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        canvas.pack(side="left", fill="both", expand=True)
        canvas.rowconfigure(0, weight=1)
        canvas.columnconfigure(0, weight=1)
        scrollbar.pack(side="right", fill="y")
        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )
        self.scrollable_frame.rowconfigure(0, weight=1)
        self.scrollable_frame.columnconfigure(0, weight=1)
        self.region=ttk.Frame(self.scrollable_frame)
        self.region.pack(fill='both', expand=1)
        self.region.grid_rowconfigure(0, weight=1)
        self.region.grid_columnconfigure(0, weight=1)

class OtherWindow():
    """data collector object and window"""
    def __init__(self, window):
            self.window=tk.Toplevel(window)
            self.window.grid_columnconfigure(0, weight=1)
            self.window.grid_columnconfigure(1, weight=1)
            self.window.grid_columnconfigure(2, weight=1)
            self.window.grid_columnconfigure(3, weight=1)
            self.window.grid_rowconfigure(3, weight=1)
            self.lbl1=ttk.Label(self.window, text="this is a sort of long label")
            self.lbl1.grid(row=0, column=0, columnspan=2)
            self.lbl2=ttk.Label(self.window, text="this is another label")
            self.lbl2.grid(row=0, column=2)
            self.lbl3=ttk.Label(self.window, text="Other information: blah blah blah blah")
            self.lbl3.grid(row=0, column=3)
            self.directions=ttk.Label(self.window, text='These are instructions that are kind of long and take'+\
'up about this much space if I had to guess so random text random text random text', wraplength=700)
            self.directions.grid(row=1, column=0, columnspan=4)
            self.scrolly=ScrollableFrame(self.window)
            self.scrolly.grid(row=2, column=0, columnspan=4,sticky='nsew')
            self.frame=self.scrolly.region
            self.fillScrollRegion()
            self.continueBtn=ttk.Button(self.window, text="Do Something", command=self.do)
            self.continueBtn.grid(row=3, column=0, columnspan=4, sticky='nsew')

    def fillScrollRegion(self):
        """fills scrollable region with label widgets"""
        for i in range(15):
            for j in range(5):
                lbl=ttk.Label(self.frame, text="Sample text"+str(i)+' '+str(j))
                lbl.grid(row=i, column=j, sticky='nsew')

    def do(self):
        pass

root=tk.Tk()
app=OtherWindow(root)
root.mainloop()
将tkinter作为tk导入
从tkinter导入ttk
类ScrollableFrame(ttk.Frame):
“摘自https://blog.tecladocode.com/tkinter-scrollable-frames/ 并修改为
允许在self.region内使用网格
类,该类允许创建可滚动的帧“”
定义初始化(self,container,*args,**kwargs):
super()
canvas=tk.canvas(self)
scrollbar=ttk.scrollbar(self,orient=“vertical”,command=canvas.yview)
self.scrollable_frame=ttk.frame(画布)
canvas.create_window((0,0),window=self.scrollable_frame,anchor=“nw”)
configure(yscrollcommand=scrollbar.set)
canvas.pack(side=“left”,fill=“both”,expand=True)
canvas.rowconfigure(0,权重=1)
canvas.columnconfigure(0,权重=1)
滚动条包装(side=“right”,fill=“y”)
self.scrollable_frame.bind(
"",
lambda e:canvas.configure(
scrollregion=canvas.bbox(“全部”)
)
)
self.scrollable_frame.rowconfigure(0,权重=1)
self.scrollable_frame.columnconfigure(0,权重=1)
self.region=ttk.Frame(self.scrollable\u Frame)
self.region.pack(fill='both',expand=1)
self.region.grid_rowconfigure(0,权重=1)
self.region.grid\u columnconfigure(0,权重=1)
类OtherWindow():
“”“数据收集器对象和窗口”“”
定义初始化(自,窗口):
self.window=tk.Toplevel(窗口)
self.window.grid\u columnconfigure(0,权重=1)
self.window.grid\u columnconfigure(1,权重=1)
self.window.grid\u columnconfigure(2,权重=1)
self.window.grid\u column配置(3,权重=1)
self.window.grid_rowconfigure(3,权重=1)
self.lbl1=ttk.Label(self.window,text=“这是一种长标签”)
self.lbl1.grid(行=0,列=0,列span=2)
self.lbl2=ttk.Label(self.window,text=“这是另一个标签”)
self.lbl2.grid(行=0,列=2)
self.lbl3=ttk.Label(self.window,text=“其他信息:诸如此类”)
self.lbl3.grid(行=0,列=3)
self.directions=ttk.Label(self.window,text='这些说明有点冗长'+\
“如果我要猜这么多随机文本,那么我就要猜这么多空间随机文本”,wraplength=700)
self.directions.grid(行=1,列=0,列span=4)
self.scrolly=ScrollableFrame(self.window)
self.scrolly.grid(行=2,列=0,列span=4,sticky='nsew')
self.frame=self.scrolly.region
self.fillScrollRegion()
self.continueBtn=ttk.Button(self.window,text=“Do Something”,command=self.Do)
self.continueBtn.grid(行=3,列=0,列span=4,sticky='nsew')
def填充区域(自身):
“”“用标签小部件填充可滚动区域”“”
对于范围(15)内的i:
对于范围(5)内的j:
lbl=ttk.Label(self.frame,text=“示例文本”+str(i)+''+str(j))
lbl.grid(行=i,列=j,sticky='nsew')
def do(自我):
通过
root=tk.tk()
app=OtherWindow(根)
root.mainloop()

问题在于滚动框架容器
Frame
没有水平填充
画布。与其费心修改一些复制/粘贴,例如scrollframe,并解释它,我只给你我的scrollframe。它实际上比您正在使用的更健壮,并且您所遇到的问题并不存在。我已经将它插入到下面的脚本版本中

您的滚动框问题的解决方案可以在我的
on\u canvas\u configure
方法中找到。它只是告诉容器框架与画布宽度相同,在画布上
事件

将tkinter作为tk导入,tkinter.ttk作为ttk导入
从输入导入可编辑
类ScrollFrame(tk.Frame):
def(self,master,scrollspeed=5,r=0,c=0,rspan=1,cspan=1,grid={},**kwargs):
框架.uuu init_uuuu(self,master,***{'width':400,'height':300,**kwargs})
#__网格
self.grid(**{'row':r,'column':c,'rowspan':rspan,'columnspan':cspan,'sticky':'nswe',**grid})
#允许用户设置宽度和/或高度
如果{'width','height'}&{*kwargs}:
自网格传播(0)
#在主网格上指定此小部件的权重
self.master.grid_row配置(r,权重=1)
self.master.grid\u列配置(c,权重=1)
#在该网格上指定self.frame权重
self.grid_rowconfigure(0,权重=1)
self.grid\u column配置(0,权重=1)
#_小部件
self.canvas=tk.canvas(self,bd=0,bg=self['bg'],highlightthickness=0,yscrollincrement=scrollspeed)
self.canvas.grid(行=0,列=0,sticky='nswe')
self.frame=tk.frame(self.canvas,**kwargs)
self.frame\u id=self.canvas.create\u window((0,0),window=self.frame,anchor=“nw”)
vsb=tk.滚动条(self,orient=“vertical”)
网格(行=0,列=1,粘性=ns')
import tkinter as tk, tkinter.ttk as ttk
from typing import Iterable

   
class ScrollFrame(tk.Frame):
    def __init__(self, master, scrollspeed=5, r=0, c=0, rspan=1, cspan=1, grid={}, **kwargs):
        tk.Frame.__init__(self, master, **{'width':400, 'height':300, **kwargs})
        
        #__GRID
        self.grid(**{'row':r, 'column':c, 'rowspan':rspan, 'columnspan':cspan, 'sticky':'nswe', **grid})
        
        #allow user to set width and/or height
        if {'width', 'height'} & {*kwargs}:
            self.grid_propagate(0)
            
        #give this widget weight on the master grid
        self.master.grid_rowconfigure(r, weight=1)
        self.master.grid_columnconfigure(c, weight=1)
        
        #give self.frame weight on this grid
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        #_WIDGETS
        self.canvas = tk.Canvas(self, bd=0, bg=self['bg'], highlightthickness=0, yscrollincrement=scrollspeed)
        self.canvas.grid(row=0, column=0, sticky='nswe')
        
        self.frame    = tk.Frame(self.canvas, **kwargs)
        self.frame_id = self.canvas.create_window((0, 0), window=self.frame, anchor="nw")
        
        vsb = tk.Scrollbar(self, orient="vertical")
        vsb.grid(row=0, column=1, sticky='ns')
        vsb.configure(command=self.canvas.yview)
        
        #attach scrollbar to canvas
        self.canvas.configure(yscrollcommand=vsb.set)

        #_BINDS
        #canvas resize
        self.canvas.bind("<Configure>", self.on_canvas_configure)
        #frame resize
        self.frame.bind("<Configure>", self.on_frame_configure)
        #scroll wheel       
        self.canvas.bind_all('<MouseWheel>', self.on_mousewheel)
        
    #makes frame width match canvas width
    def on_canvas_configure(self, event):
        self.canvas.itemconfig(self.frame_id, width=event.width)
        
    #when frame dimensions change pass the area to the canvas scroll region
    def on_frame_configure(self, event):
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))
    
    #add scrollwheel feature
    def on_mousewheel(self, event):
        self.canvas.yview_scroll(int(-event.delta / abs(event.delta)), 'units')

    #configure self.frame row(s)
    def rowcfg(self, index, **options):
        index = index if isinstance(index, Iterable) else [index]
        for i in index:
            self.frame.grid_rowconfigure(i, **options)
        #so this can be used inline
        return self
        
    #configure self.frame column(s)
    def colcfg(self, index, **options):
        index = index if isinstance(index, Iterable) else [index]
        for i in index:
            self.frame.grid_columnconfigure(i, **options)
        #so this can be used inline
        return self
        

class AuxiliaryWindow(tk.Toplevel):
    def __init__(self, master, **kwargs):
        tk.Toplevel.__init__(self, master, **kwargs)
        self.geometry('600x300+600+200')
        self.attributes('-topmost', True)
        self.title('This Is Another Title') #:D
            
        #if you reconsider things, you can accomplish more with less
        labels = ["this is a sort of long label",
                  "this is another label",
                  "Other information: blah blah blah blah"]
                  
        for i, text in enumerate(labels):
            ttk.Label(self, text=text).grid(row=0, column=i)
            self.grid_columnconfigure(i, weight=1)
        
        #doing it this way the text will always fit the display as long as you give it enough height to work with
        instr = tk.Text(self, height=3, wrap='word', bg='gray94', font='Arial 8 bold', bd=0, relief='flat')
        instr.insert('1.0', ' '.join(['instructions']*20))
        instr.grid(row=1, columnspan=3, sticky='nswe')
        
        #instantiate the scrollframe, configure the first 5 columns and return the frame. it's inline mania! :p
        self.scrollframe = ScrollFrame(self, 10, 2, 0, cspan=3).colcfg(range(5), weight=1).frame
        
        self.fillScrollRegion()
        
        #why store a reference to this? Do you intend to change/delete it later?
        ttk.Button(self, text="Do Something", command=self.do).grid(row=3, columnspan=3, sticky='ew')

    def fillScrollRegion(self):
        """fills scrollable region with label widgets"""
        r, c = 30, 5    #math is our friend
        for i in range(r*c):
            ttk.Label(self.scrollframe, text=f"row_{i%r} col_{i//r}").grid(row=i%r, column=i//r, sticky='nsew')
               
    def do(self):
        pass
        

class Root(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.geometry('+550+150')
        self.title('This Is A Title Probably Or Something') #:D
        
        aux = AuxiliaryWindow(self)
        
        self.mainloop()


Root() if __name__ == "__main__" else None