Python Tkinter binding child widgets

I have made a tkinter window that is separated by two scrollable Canvas with its widgets inside. Both canvas widgets has its own scrollbar and I have binded the <MouseWheel> event on every canvas to the scrollbar.

This cause that if the mouse is on the canvas, the scroll works well, but if the mouse is over a widget inside the canvas, it doesn't activate the event handler. I have tried binding with bind_all:

canvas1.bind_all("<MouseWheel>",scrollcanvas1)
canvas2.bind_all("<MouseWheel>",scrollcanvas2)

But it activates both event handlers on every part on the window, so it doesn't works for me.

Another way to keep this work is with the <Motion> event, so when the mouse is over one canvas, the event activate the bind_all function of the canvas where the mouse is over and de-activate the other.

def enablecanvas1():
    canvas1.bind_all("<MouseWheel>",scrollcanvas1)
    canvas2.unbind("<MouseWheel>")

def enablecanvas2():
    canvas2.bind_all("<MouseWheel>",scrollcanvas2)
    canvas1.unbind("<MouseWheel>")

canvas1.bind("<Motion>",enablecanvas1)
canvas2.bind("<Motion>",enablecanvas2)

It works well, but the thing turns complicated if the widgets inside the canvas fill it, so it doesn't left any canvas surface to put the mouse over it and activate the handler.

So, is there any way to bind the handler to all the canvas child widgets to make this work?

Thanks.

Upvotes: 4

Views: 1700

Answers (2)

Mike - SMT
Mike - SMT

Reputation: 15226

Here is an example of how you can set up multiple scrolling canvas and bind the mouse wheel to each. The way I would do this is to change bind_all on mouse enter of a frame containing the canvas.

I have it set up in a way that each frame and canvas will expand with the window and you can see how everything inside scrolls just fine no matter what your mouse is over inside of the frame.

Try this code and let me know what you think.

import tkinter as tk

root = tk.Tk()
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)

def on_mousewheel1(event):
    canvas.yview_scroll(int(-1*(event.delta/120)), "units")

def on_mousewheel2(event):
    canvas2.yview_scroll(int(-1*(event.delta/120)), "units")

def set_binds_canvas1(event):
    frame.bind_all("<MouseWheel>", on_mousewheel1)

def set_binds_canvas2(event):
    frame2.bind_all("<MouseWheel>", on_mousewheel2)

# setup for first canvas
frame = tk.Frame(root)
frame.rowconfigure(0, weight=1)
frame.columnconfigure(0, weight=1)
frame.grid(row=0,column=0, sticky="nsew")

canvas = tk.Canvas(frame, scrollregion=(0,0,500,500))
canvas.grid(row=0, column=0, sticky="nsew")

lbl = tk.Label(canvas, text="Some random text!")
entry = tk.Entry(canvas)
txt = tk.Text(canvas)

canvas.create_window((100, 100), window=lbl)
canvas.create_window((100, 50), window=entry)
canvas.create_window((350, 400), window=txt)

vbar=tk.Scrollbar(frame, orient="vertical")
vbar.grid(row=0, column=1, sticky="ns")
vbar.config(command=canvas.yview)
canvas.config(yscrollcommand=vbar.set)

# setup for second canvas
frame2 = tk.Frame(root)
frame2.rowconfigure(0, weight=1)
frame2.columnconfigure(0, weight=1)
frame2.grid(row=0,column=1, sticky="nsew")

canvas2 = tk.Canvas(frame2, scrollregion=(0,0,500,500))
canvas2.grid(row=0, column=0, sticky="nsew")

lbl2 = tk.Label(canvas2, text="Some random text!")
entry2 = tk.Entry(canvas2)
txt2 = tk.Text(canvas2)

canvas2.create_window((100, 100), window=lbl2)
canvas2.create_window((100, 50), window=entry2)
canvas2.create_window((350, 400), window=txt2)

vbar2=tk.Scrollbar(frame2, orient="vertical")
vbar2.grid(row=0, column=1, sticky="ns")
vbar2.config(command=canvas2.yview)
canvas2.config(yscrollcommand=vbar2.set)

frame.bind("<Enter>", set_binds_canvas1)
frame2.bind("<Enter>", set_binds_canvas2)

root.mainloop()

Upvotes: 3

Bryan Oakley
Bryan Oakley

Reputation: 385980

I would say that the best solution is to use bind_all. Within the bound function you first need to figure out which canvas the mouse is over (and/or, which canvas has the focus), and then you can scroll that canvas.

Upvotes: 2

Related Questions