问题描述
tkinter.Text
小部件允许将其他小部件(例如按钮)与纯文本一起插入。
tkinter.Text
小部件通过滚动内容来响应鼠标滚轮。但是,如果光标恰好位于子窗口小部件上,则该窗口小部件将获得鼠标滚轮事件,并且Text
不会滚动。相反,我希望Text
获得此鼠标滚轮事件。
这是tkinter.Text
内小部件的默认行为,但这是一些代码来演示该问题。
import tkinter as tk
root = tk.Tk()
s = '\nTesting mouse wheel scroll with widgets inside tkinter.Text.\n'
txt = tk.Text(root,width=40,height=6)
for i in range(5):
b = tk.Button(txt,text='I Break Scroll')
txt.window_create(tk.END,window=b,padx=5,pady=5)
txt.insert(tk.END,s)
txt.pack()
root.mainloop()
解决方法
MouseWheel事件发送到光标下方的小部件。这样就可以用鼠标控制多个可滚动的小部件。在较旧的tkinter版本中,它会以焦点滚动窗口。
对于不可滚动的小部件,没有默认行为。当您在按钮或标签上移动鼠标滚轮时,滚动将停止,因为事件将转到按钮或标签上而不是文本上。
您似乎不希望出现这种情况,因此需要为不可滚动的小部件的鼠标滚轮提供自己的绑定。如果将这些绑定应用于窗口小部件类而不是单个窗口小部件,则不必绑定到每个单独的窗口小部件。不过,您可以根据需要绑定到各个小部件。
下面是一个示例,该示例为Button
和Label
小部件类添加绑定以将事件传递给其父级。
import tkinter as tk
root = tk.Tk()
text = tk.Text(root,wrap="word")
vsb = tk.Scrollbar(root,command=text.yview)
text.configure(yscrollcommand=vsb.set)
vsb.pack(side="right",fill="y")
text.pack(side="left",fill="both",expand=True)
for i in range(200):
text.insert("end",f"Item #{i}")
if i%5 == 0:
b = tk.Button(text,text=f"A button")
text.window_create("end",window=b)
elif i%3 == 0:
l = tk.Button(text,text=f"A label")
text.window_create("end",window=l)
text.insert("end","\n")
def scroll_parent(event):
parent = root.nametowidget(event.widget.winfo_parent())
parent.event_generate("<MouseWheel>",delta=event.delta,when="now")
root.bind_class("Button","<MouseWheel>",scroll_parent)
root.bind_class("Label",scroll_parent)
root.mainloop()
注意:如果您使用的是基于X11的系统,则需要调整此代码以绑定到<Button-4>
和<Button-5>
而不是<MouseWheel>
。