英文:
Why would the ttk widget only appears after there is a configuration change event and not when the button is pressed?
问题
Can you help me understand why the ttk.Checkbutton
widget does not appear after the ttk.Button
widget is pressed? The ttk.Checkbutton
widget would only appear when there is a configuration change event, for example after moving the sash of the ttk.PanedWindow
widget or by resizing the root window. Or, when the height of self.f2
is less than the Checkbutton. This code uses a vertical scroll frame which is saved in the file named scrframe.py
Test Code:
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()
Issue: Checkbutton does not appear immediately when the height of self.f2
is greater than the Checkbutton.
Checkbutton appears immediately when the height of self.f2
is less than the Checkbutton:
英文:
Can you help me understand why the ttk.Checkbutton
widget does not appear after the ttk.Button
widget is pressed? The ttk.Checkbutton
widget would only appear when there is a configuration change event, for example after moving the sash of the ttk.PanedWindow
widget or by resizing the root window. Or, when the height of self.f2
is less than the Checkbutton. This code uses a vertical scroll frame which is saved in the file named scrframe.py
Test Code:
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()
Issue: Checkbutton does not appears immediately when the height of self.f2
is greater than the Checkbutton.
Checkbutton appears immediately when the height of self.f2
is less than the Checkbutton:
答案1
得分: 0
感谢@acw1668的评论。看起来问题源于scrframe.py中的._configure_canvas
事件处理程序只使用了canvas.winfo_reqwidth()
。下面是在释放按钮后打印出的值:
def _configure_interior(event):
interior.winfo_reqwidth()=228 interior.winfo_reqheight()=165
canvas.winfo_reqwidth()=1 canvas.winfo_reqheight()=223
event.width=261 event.height=165
do_something was called
它们显示以前包含self.interior
(一个ttk.Frame
小部件)的“画布窗口对象”的宽度由于canvas.winfo_reqwidth()=1
而误设置为1像素宽度,因此ttk.Checkbutton
小部件被隐藏了。
经过进一步测试,我发现仅仅使用event.width
并不是一个健壮的解决方案。在Tk
窗口宽度小于Checkbutton的宽度的情况下,当水平滚动Canvas时,Checkbutton的外观将被截断。
因此,用于“画布窗口对象”的正确宽度应该是canvas.winfo_reqwidth()
和event.width
的最大值。
def _configure_canvas(event):
print(f"\ndef _configure_canvas(event):")
print(f"{interior.winfo_reqwidth()=} {interior.winfo_reqheight()=}")
print(f"{canvas.winfo_reqwidth()=} {canvas.winfo_reqheight()=}")
print(f"{event.width=} {event.height=}")
if interior.winfo_reqwidth() != canvas.winfo_width():
# 更新画布窗口对象的宽度为canvas.winfo_reqwidth()和event.width的最大值
maxwidth = max([canvas.winfo_reqwidth(), event.width])
canvas.itemconfigure(interior_id, width=maxwidth)
使用event.width
的结果:
使用max([canvas.winfo_reqwidth(), event.width])
的结果:
英文:
Thanks to the comments by @acw1668. It looks like the issue stems from the ._configure_canvas
event handler in scrframe.py simply using canvas.winfo_reqwidth()
. Below are printed-out values after the Button is released:
def _configure_interior(event):
interior.winfo_reqwidth()=228 interior.winfo_reqheight()=165
canvas.winfo_reqwidth()=1 canvas.winfo_reqheight()=223
event.width=261 event.height=165
do_something was called
They showed that previously the width of the "canvas window objected" that contained self.interior
(a ttk.Frame
widget) was mistakenly set to 1 pixels width since canvas.winfo_reqwidth()=1
hence the ttk.Checkbutton
widget was hidden.
After further testing, I discovered that simply using event.width
is not a robust solution. In the situation when the Tk
window width is less than the width of the Checkbutton, the appearance of the Checkbutton will be truncated when the Canvas is scrolled horizontally.
Hence, the correct width to use for the "canvas window objected" should instead be the max of canvas.winfo_reqwidth()
and event.width
.
def _configure_canvas(event):
print(f"\ndef _configure_canvas(event):")
print(f"{interior.winfo_reqwidth()=} {interior.winfo_reqheight()=}")
print(f"{canvas.winfo_reqwidth()=} {canvas.winfo_reqheight()=}")
print(f"{event.width=} {event.height=}")
if interior.winfo_reqwidth() != canvas.winfo_width():
# update the canvas window object's width to the max of canvas.winfo_reqwidth() and event.width
maxwidth = max([canvas.winfo_reqwidth(), event.width])
canvas.itemconfigure(interior_id, width=maxwidth)
Outcome from using event.width
:
Outcome from using max([canvas.winfo_reqwidth(), event.width])
:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论