为何ttk.Checkbutton点击按钮后不显示,仅配置变化时才出现?
点击ttk.Button组件后,ttk.Checkbutton组件不会立即显示,只有在发生配置变化事件(比如移动ttk.PanedWindow的窗格条、调整根窗口大小),或者当self.f2的高度小于Checkbutton时,该组件才会出现。代码使用了scrframe.py文件中的VerticalScrollFrame(垂直滚动框架)。
测试代码
import tkinter as tk from tkinter import ttk from PIL import Image, ImageTk from scrframe import VerticalScrollFrame class App(ttk.PanedWindow): def __init__(self, parent, orient="vertical"): super().__init__(parent, orient=orient) self.parent = parent self.after_id = None self.f1 = ttk.Frame(self, style="Top.TFrame") self.f2 = VerticalScrollFrame(self, background='green') self.add(self.f1) self.add(self.f2) self.b1 = ttk.Button(self.f1, text="Button", command=self.load_image, width=30) self.b1.grid(row=0, column=0, sticky="nsew", padx=5, pady=5) self.f1.bind("<Configure>", self.schedule_event) self.f2.bind("<Configure>", self.schedule_event) self.bind("<<SashMoved>>", self.do_something) # Event handlers def schedule_event(self, event): if self.after_id: self.after_cancel(self.after_id) self.after_id = self.after(500, self.event_generate, "<<SashMoved>>") def do_something(self, event): print("do_something was called") def load_image(self): im = '/home/user/Pictures/image.jpeg' im = Image.open(im) im.thumbnail((200, 200)) self.thumbnail = ImageTk.PhotoImage(im) self.thumbnail.image = im self.cb = ttk.Checkbutton(self.f2.interior, text="Image", image=self.thumbnail, compound="top") self.cb.grid(row=0, column=0, padx=5, pady=5) self.update_idletasks() # Does not work if __name__ == '__main__': root = tk.Tk() ss = ttk.Style() ss.configure('Top.TFrame', background="red") app = App(root) app.pack(fill="both", expand=True) root.mainloop()
问题现象
当
self.f2的高度大于Checkbutton时,Checkbutton不会立即显示:
当
self.f2的高度小于Checkbutton时,Checkbutton会立即显示:
原因分析
这是因为你使用的VerticalScrollFrame(基于Canvas和Scrollbar实现的滚动框架)在添加新组件后,没有自动触发Canvas滚动区域的更新和视口重绘:
- 当
self.f2高度小于Checkbutton时,新组件的尺寸超出了滚动框架的可视区域,此时滚动框架会自动调整Canvas的滚动区域,触发重绘流程,所以Checkbutton立刻显示; - 当
self.f2高度足够大时,新组件没有超出可视区域,滚动框架不会主动更新Canvas的滚动区域,也不会触发重绘,因此组件要等到窗口配置变化(调整大小、移动窗格)时才会被渲染。
解决方法
在load_image方法中,添加更新滚动区域的代码,强制触发滚动框架的重绘:
修改后的load_image方法:
def load_image(self): im = '/home/user/Pictures/image.jpeg' im = Image.open(im) im.thumbnail((200, 200)) self.thumbnail = ImageTk.PhotoImage(im) self.thumbnail.image = im self.cb = ttk.Checkbutton(self.f2.interior, text="Image", image=self.thumbnail, compound="top") self.cb.grid(row=0, column=0, padx=5, pady=5) # 先更新内部容器的布局,再调整Canvas的滚动区域 self.f2.interior.update_idletasks() self.f2.canvas.configure(scrollregion=self.f2.canvas.bbox("all"))
如果你的VerticalScrollFrame类提供了专门的更新方法(比如update_scrollregion),直接调用该方法会更规范。
内容的提问来源于stack exchange,提问作者Sun Bear
相关产品推荐
相关产品推荐

