【问题标题】:tkinter scrollregion not updatingtkinter 滚动区域不更新
【发布时间】:2020-03-09 03:03:44
【问题描述】:

我试图让滚动条在我的 tkinter 应用程序中使用之前的帖子:Adding a scrollbar to a group of widgets in Tkinter。 如果我在 for 循环之前取消注释代码,一切都会正常工作,但据我(有限的)理解,我相信如果我取消注释 for 循环内的代码,它也应该工作。 据我了解,调用canvas.configure(scrollregion=canvas.bbox("all")) 应该更新画布的滚动区域以包含放置在框架内的所有标签小部件。第一个只是在每次使用frame.bind("<Configure>",onFrameConfigure) 将新标签小部件添加到框架时自动执行,而第二个手动执行,那么有什么区别?为什么它不起作用?

import tkinter

root = tkinter.Tk()
canvas = tkinter.Canvas(root)
frame = tkinter.Frame(canvas)

scrollbar=tkinter.Scrollbar(root,orient="vertical",command=canvas.yview)
canvas.configure(yscrollcommand=scrollbar.set)

scrollbar.pack(side="right", fill="y")
canvas.pack(fill="both", expand=True)

canvas.create_window((0, 0), window=frame, anchor="nw")

# works 
#def onFrameConfigure(event):
#    canvas.configure(scrollregion=canvas.bbox("all"))
# 
#frame.bind("<Configure>", onFrameConfigure)

for x in range(100):

     new_label = tkinter.Label(frame, text="%d"%x)
     new_label.pack()

     # doesn't work
     #canvas.configure(scrollregion=canvas.bbox("all"))

root.mainloop()

【问题讨论】:

    标签: python tkinter


    【解决方案1】:

    第一个只是在每次使用 frame.bind("",onFrameConfigure) 将新的标签小部件添加到框架时自动执行,而第二个是手动执行,那么有什么区别?为什么它不起作用?

    不同之处在于调用bbox 以响应事件发生在帧实际绘制在屏幕上之后。在循环中调用它意味着它被调用之前小部件可见并且它们的大小是不确定的。

    如果您在循环内调用update_idletasks(或者可能是update,取决于平台)强制在屏幕上绘制小部件,则在循环内调用bbox 将起作用。不过,在循环完成后立即调用它会更有效率,这样在添加所有小部件后调用一次。

    【讨论】:

    • 感谢Bryan的回答,刚才我也发现了这个问题stackoverflow.com/questions/42237310/…,刚刚在外面做了root.update()然后canvas.configure(scrollregion=canvas.bbox("all")) for 循环,它工作,谢谢。
    • 另外,顺便说一下,我想知道为什么在回调函数内部不需要 root.update() 在调用盒子?我认为事件参数与此有关。我搜索了一下,发现了这个:stackoverflow.com/questions/29158220/… 所以 root.mainloop() 实际上做了一些事件处理?那么框架是否仅在 root.mainloop() 处绘制?它会执行“root.update”,然后调用回调,这样就不需要 root.update()?
    • 另外,你说bbox应该在绘制完之后调用,但是pack()不是已经绘制并放置在框架上吗?所以 pack() 实际上并没有画东西,但实际上是 root.mainloop() 做的?那么,只有 root.update_idletasks()、root.update() 和 root.mainloop() 绘制东西吗?是对的吗? pack() 实际上并没有画东西,它只是“放置”它们?
    • @JJP7: “所以 root.mainloop() 实际上做了一些事件处理” - root.mainloop() 做了 all 事件处理。除了按钮点击和键盘输入之外,重绘屏幕的请求是它处理的一种类型的事件。当它必须绘制或重绘一个小部件时,它会在完成后生成一个&lt;Configure&gt; 事件。因此,根据定义,将在绘制小部件后调用回调。这就是您不必在回调中调用update 的原因。
    • @JJP7:“pack() 不是已经绘制并将它们放在框架上吗?” - 不完全是。它请求在屏幕上绘制小部件。请求被添加到事件队列中。在允许 mainloop 处理这些事件之前,或者直到您通过调用 update 明确要求 tkinter 处理这些事件之前,这些更改将不可见。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    • 1970-01-01
    • 2018-06-28
    • 1970-01-01
    • 2015-04-03
    相关资源
    最近更新 更多