Tkinter动态滚动条,用于动态GUI,无法使用GUI

时间:2017-10-30 05:58:33

标签: python tkinter

这与之前的问题有关: Tkinter dynamically 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()

如果窗口完全展开,这就是窗口的样子

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

滚动条不正确(滚动条出现时)

1 个答案:

答案 0 :(得分:3)

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

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

self.frame.bind("<Configure>", self.reset_scrollregion)

然后,将此功能添加到ScrollFrame

def reset_scrollregion(self, event):
    self.canvas.configure(scrollregion=self.canvas.bbox("all")