You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TTK滚动条更新异常求助:滚动区域未适配新内容

动态调整Entry行数时滚动条scrollregion适配异常

使用ttk构建GUI界面,通过Scale组件与Spinbox组件动态调整Entry组件的行数。当条目数量超过窗口尺寸时,采用Canvas组件搭配滚动条进行适配——无论是否启用滚动条,所有条目都放置在entriesFrame内的innerFrame中。

当前存在的问题:滚动条虽能触发更新,但始终适配之前的bbox尺寸,无法正确匹配当前条目高度。

已知正常功能:

  • Scale与Spinbox协同工作正常,可精准控制条目数量
  • 固定条目数时,滚动条与Entry组件完全可用,条目能正确生成并显示(可修改root.geometry("275x350")验证)

推测问题根源在于scrollregion的配置逻辑。

相关代码如下:

from tkinter import Canvas, Tk, LEFT, BOTH, RIGHT, VERTICAL, X, Y, ALL, IntVar, TOP
from tkinter.ttk import Frame, Scale, Entry, Scrollbar, Spinbox

def validateSpin(P):
    if (P.isdigit() or P =="" ) and int(P) > 0 and int(P) < 11:
        return True
    else:
        return False
def updateScale(event):
    def inner():
        spnVal = spin.get()
        if spnVal != "":
            scale.set(float(spnVal))
            entries.set(float(spnVal))
            refreshEntries()
    root.after(1, inner)
def updateSpin(event):
    def inner():
        reportVal = round(float(scale.get()))
        spin.set(reportVal)
        entries.set(reportVal)
        refreshEntries()
    root.after(1, inner)
def scrollbarNeeded():
    if entries.get() > 7:
        return True
    else:
        return False
def makeScrollbarAndCanvas():
    scrollingCanvas = Canvas(entriesFrame, width = 200, highlightthickness=0)
    scrollingCanvas.pack(side=LEFT,fill=X,expand=1)
    
    scrollbar = Scrollbar(entriesFrame, orient=VERTICAL,command=scrollingCanvas.yview)
    scrollbar.pack(side=RIGHT,fill=Y)
    
    scrollingCanvas.configure(yscrollcommand=scrollbar.set)
    scrollingCanvas.bind("<Configure>",lambda e: scrollingCanvas.config(scrollregion=scrollingCanvas.bbox(ALL)))
    
    innerFrame = Frame(scrollingCanvas)
    innerFrame.bind("<Map>", lambda e: scrollingCanvas.config(scrollregion=scrollingCanvas.bbox(ALL)))
    scrollingCanvas.create_window((0,0),window= innerFrame, anchor="nw")
    
    return innerFrame
def scrollbarFound():
    for child in entriesFrame.pack_slaves():
        if isinstance(child, Canvas):
            return True
    return False
def populateEntries(frm):
    for i in range(entries.get()):
        E = Entry(frm, width=15)
        E.grid(column=0, row = i, pady=2)

def refreshEntries():
    def searchAndDestory(obj):
        if hasattr(obj, 'winfo_children') and callable(getattr(obj, 'winfo_children')):
            for child in obj.winfo_children():
                searchAndDestory(child)
            obj.destroy()
        elif isinstance(obj, list):
            for child in obj:
                searchAndDestory(child)
        else:
            obj.destroy()
    if scrollbarNeeded():
        if scrollbarFound():
            print(entriesFrame.winfo_children().reverse())
            for child in entriesFrame.winfo_children():
                if isinstance(child, Canvas):
                    frm = child.winfo_children()[0]
                    searchAndDestory(frm.grid_slaves())
                    populateEntries(frm)
                    child.config(scrollregion=child.bbox(ALL))
        else:
            searchAndDestory(entriesFrame.winfo_children()[0])
            populateEntries(makeScrollbarAndCanvas())
    else:
        searchAndDestory(entriesFrame.winfo_children())
        innerFrame = Frame(entriesFrame)
        populateEntries(innerFrame)
        innerFrame.pack(fill=BOTH)

root = Tk()
root.resizable(False,False)
root.geometry("275x250")

outerFrame = Frame(root, padding = 10)

entries = IntVar()
entries.set(5)

topFrame = Frame(outerFrame, padding = 10)

spin = Spinbox(topFrame, from_=1, to=10, validate="key", validatecommand=(topFrame.register(validateSpin), "%P"))
spin.grid(column=0, row=0)
spin.set(entries.get())
spin.bind("<KeyRelease>", updateScale)
spin.bind("<ButtonRelease>", updateScale)
spin.bind("<MouseWheel>", updateScale)

scale = Scale(topFrame, from_=1, to=10)
scale.grid(column=1, row=0)
scale.set(entries.get())
scale.bind("<Motion>", updateSpin)
scale.bind("<ButtonRelease>", updateSpin)

topFrame.pack(side=TOP, fill=BOTH)
entriesFrame = Frame(outerFrame)
refreshEntries()
entriesFrame.pack(fill=BOTH)
outerFrame.pack(fill=BOTH)

root.mainloop()

内容的提问来源于stack exchange,提问作者Max Friedman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 14:57:03