tkinter.Text 内的小部件破坏了鼠标滚轮
Widgets inside tkinter.Text break mouse wheel
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 中,它使用焦点滚动 window。
对于不可滚动的小部件,没有默认行为。当您在按钮或标签上移动鼠标滚轮时,滚动停止,因为事件转到按钮或标签而不是文本。
看来您不希望出现这种情况,因此您需要为 non-scrollable 小部件的鼠标滚轮提供自己的绑定。如果您将这些绑定应用到小部件 class 而不是单独的小部件,那么您将不必绑定到每个单独的小部件。不过,您可以根据需要绑定到各个小部件。
下面是一个示例,它为 Button
和 Label
小部件 class 添加绑定以将事件传递给其父级。
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", "<MouseWheel>", scroll_parent)
root.mainloop()
注意:如果您使用的是基于 X11 的系统,则需要调整此代码以绑定到 <Button-4>
和 <Button-5>
而不是 <MouseWheel>
。
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 中,它使用焦点滚动 window。
对于不可滚动的小部件,没有默认行为。当您在按钮或标签上移动鼠标滚轮时,滚动停止,因为事件转到按钮或标签而不是文本。
看来您不希望出现这种情况,因此您需要为 non-scrollable 小部件的鼠标滚轮提供自己的绑定。如果您将这些绑定应用到小部件 class 而不是单独的小部件,那么您将不必绑定到每个单独的小部件。不过,您可以根据需要绑定到各个小部件。
下面是一个示例,它为 Button
和 Label
小部件 class 添加绑定以将事件传递给其父级。
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", "<MouseWheel>", scroll_parent)
root.mainloop()
注意:如果您使用的是基于 X11 的系统,则需要调整此代码以绑定到 <Button-4>
和 <Button-5>
而不是 <MouseWheel>
。