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
相关产品推荐
相关产品推荐

