为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

叮当猫咪 2023-08-15 16:40:35
我有一个可滚动框架类,是从我发现的一些代码中借用的,但我无法调整它以满足我的需求。它是由 .pack() 管理的,但我需要使用 .grid(),所以我只是将一个框架 ( self.region) 打包到其中,这样我就可以在其中网格化我的小部件。但是,该框架内的小部件不会扩展以符合容器的边缘,我不确定为什么。那里有很多与我类似的问题,但似乎没有一个解决方案有帮助。我尝试使用.grid_columnconfigure、.columnconfigure()、 ,但.bind("Configure")都无济于事。有没有人有任何建议让我的可滚动区域中的小部件向东和向西扩展以填充窗口?import tkinter as tkfrom tkinter import ttkclass 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)
查看完整描述

1 回答

?
慕姐4208626

TA贡献1852条经验 获得超7个赞

问题是滚动框架容器Frame没有Canvas水平填充。我不会费心修复一些复制/粘贴(例如滚动框架)并解释它,而是只给您我的滚动框架。它比您正在使用的要强大得多,而且您遇到的问题并不存在。我已经将其插入到下面的脚本版本中。

在我的方法中找到了滚动框架问题的解决方案on_canvas_configure。它只是告诉容器框架在画布事件上与画布宽度相同<Configure>

https://img1.sycdn.imooc.com//64db3a5100016da306280357.jpg

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


查看完整回答
反对 回复 2023-08-15
  • 1 回答
  • 0 关注
  • 96 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信