Reputation: 3512
tkinter.Text
widget allows other widgets, such as buttons, to be inserted along with plain text.
tkinter.Text
widget responds to mouse wheel by scrolling the contents. However, if the cursor happens to be over a child widget, that widget gets the mouse wheel event and the Text
does not scroll. Instead, I want the Text
to get this mouse wheel event.
What is a good way to fix this?
This is default behavior for widgets inside tkinter.Text
, but here is some code to demonstrate the problem.
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()
Upvotes: 0
Views: 560
Reputation: 386265
MouseWheel events are sent to the widget under the cursor. This makes it possible to control multiple scrollable widgets with the mouse. In older versions of tkinter it scrolled the window with the focus.
For widgets that aren't scrollable, there is no default behavior. When you move the mouse wheel while over a button or label the scrolling stops, since the event goes to the button or label rather than the text.
It appears you don't want this behavior, so you need to provide your own bindings for the mouse wheel for non-scrollable widgets. If you apply these bindings to the widget class rather than individual widgets then you won't have to bind to every individual widget. Though, you could bind to individual widgets if you wish.
Here's an example that adds bindings for the Button
and Label
widget classes to pass the event along to its parent.
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()
Note: if you are on an X11-based system you'll need to adjust this code to bind to <Button-4>
and <Button-5>
rather than <MouseWheel>
.
Upvotes: 3