动态 GUI 的 Tkinter 动态滚动条不随 GUI 更新

WCT*_*ech 3 python tkinter

这与上一个问题有关: Tkinter dynamic create widgets from button

在我问上一个问题的时候,我相信在动态 GUI 周围添加一个可滚动的框架会很容易。相反,我遇到了一个问题,即在按下按钮后滚动条没有检测到新框架和输入框。如何在不大量编辑 ScrollFrame 类的情况下解决这个问题?

我知道 Scrollbarframe 可以与其他小部件一起使用,只是动态组件导致了问题。当我缩小窗口的垂直大小超过 createWidgets 按钮的原始位置时,会出现滚动条,但其余动态创建的小部件不存在滚动条。画布是否没有检测到框架的垂直尺寸随着按钮的按下而增加?

注意:我知道通配符导入很糟糕。我只是使用一个作为例子

from tkinter import *

class AutoScrollbar(Scrollbar):
   # A scrollbar that hides itself if it's not needed.
   # Only works if you use the grid geometry manager!
    def set(self, lo, hi):
        if float(lo) <= 0.0 and float(hi) >= 1.0:
            # grid_remove is currently missing from Tkinter!
            self.tk.call("grid", "remove", self)
        else:
            self.grid()
        Scrollbar.set(self, lo, hi)
    def pack(self, **kw):
        raise TclError("cannot use pack with this widget")
    def place(self, **kw):
        raise TclError("cannot use place with this widget")

class ScrollFrame:
    def __init__(self, master):

        self.vscrollbar = AutoScrollbar(master)
        self.vscrollbar.grid(row=0, column=1, sticky=N+S)
        self.hscrollbar = AutoScrollbar(master, orient=HORIZONTAL)
        self.hscrollbar.grid(row=1, column=0, sticky=E+W)

        self.canvas = Canvas(master, yscrollcommand=self.vscrollbar.set, 
                        xscrollcommand=self.hscrollbar.set)
        self.canvas.grid(row=0, column=0, sticky=N+S+E+W)

        self.vscrollbar.config(command=self.canvas.yview)
        self.hscrollbar.config(command=self.canvas.xview)

        # make the canvas expandable
        master.grid_rowconfigure(0, weight=1)
        master.grid_columnconfigure(0, weight=1)

        # create frame inside canvas
        self.frame = Frame(self.canvas)
        self.frame.rowconfigure(1, weight=1)
        self.frame.columnconfigure(1, weight=1)

    def update(self):
        self.canvas.create_window(0, 0, anchor=NW, window=self.frame)
        self.frame.update_idletasks()
        self.canvas.config(scrollregion=self.canvas.bbox("all"))

        if self.frame.winfo_reqwidth() != self.canvas.winfo_width():
            # update the canvas's width to fit the inner frame
            self.canvas.config(width = self.frame.winfo_reqwidth())
        if self.frame.winfo_reqheight() != self.canvas.winfo_height():
            # update the canvas's width to fit the inner frame
            self.canvas.config(height = self.frame.winfo_reqheight())
frames = []
widgets = []            

def createwidgets():
    global widgetNames
    global frameNames

    frame = Frame(o.frame, borderwidth=2, relief="groove")
    frames.append(frame)

    frame.pack(side="top", fill="x")

    widget = Entry(frame)
    widgets.append(widget)

    widget.pack(side="left")

root = Tk()
o = ScrollFrame(root)
label = Label(o.frame, text = "test")
label1 = Label(o.frame, text = "test")
label2 = Label(o.frame, text = "test")
label3 = Label(o.frame, text = "test")
label.pack()
label1.pack()
label2.pack()
label3.pack()


createWidgetButton = Button(o.frame, text="createWidgets", 
command=createwidgets)
createWidgetButton.pack(side="bottom", fill="x")

o.update()
root.mainloop()
Run Code Online (Sandbox Code Playgroud)

这是窗口完全展开后的样子

如果我要缩小窗口,它应该立即创建一个垂直滚动条,因为它会覆盖一个小部件。但是,滚动条就像程序仍处于初始状态一样。

不正确的滚动条(在滚动条出现的那一刻)

Bry*_*ley 7

scrollregion每当您将小部件添加到内部框架时,您都需要确保更新画布。最常见的解决方案是绑定到框架的<Configure>事件,该事件将在框架改变大小时触发。

ScrollFrame.__init__创建框架后添加以下行:

self.frame.bind("<Configure>", self.reset_scrollregion)
Run Code Online (Sandbox Code Playgroud)

然后,将此函数添加到ScrollFrame

def reset_scrollregion(self, event):
    self.canvas.configure(scrollregion=self.canvas.bbox("all")
Run Code Online (Sandbox Code Playgroud)