Make Tkinter canvas respond to MouseWheel event

W

WaterWalk

Hello. When I tried to make Tkinter canvas widget respond to
MouseWheel event on Windows XP, I failed. The canvas just doesn't
receive MouseWheel event. I used bind_all to find out which widget
receives this event and the result showed that only the top Tk widget
gets it. This is really annoying. I wonder if this problem exists on
other platform. I googled, but found no appliable solution, so I wrote
one as following. It's not perfect, but works well for me. Please
comment on my implementation, and if you have better solution, please
show it.

In this implementation, I bind the MouseWheel to the toplevel window
which contains the canvas.
To test if the canvas shall scroll, I check if the coordinates of the
mouse is within the canvas.

from Tkinter import *

class ScrolledCanvas(Canvas):
def __init__(self, parent, xscroll=False, yscroll=False, *args,
**kargs):
frm = Frame(parent)
frm1 = Frame(frm)
Canvas.__init__(self, frm1, *args, **kargs)
self.pack(side=LEFT, fill=BOTH, expand=YES)

frm1.pack(side=TOP, fill=BOTH, expand=YES)
frm2 = Frame(frm)
frm2.pack(side=BOTTOM, expand=YES, fill=X)

if xscroll:
xsbar = Scrollbar(frm2)
xsbar.config(orient=HORIZONTAL)
xsbar.config(command=self.xview)
self.config(xscrollcommand=xsbar.set)
xsbar.pack(fill=BOTH, expand=YES)
self.winfo_toplevel().bind('<Control-MouseWheel>',
self.onMouseWheelX)
if yscroll:
ysbar = Scrollbar(frm1)
ysbar.config(orient=VERTICAL)
ysbar.config(command=self.yview)
self.config(yscrollcommand=ysbar.set)
ysbar.pack(side=RIGHT, fill=BOTH, expand=YES)
self.winfo_toplevel().bind('<MouseWheel>',
self.onMouseWheelY)
self.pack = frm.pack # because the canvas is not contained in
a frame
self.canvasFrame = frm
def onMouseWheelY(self, event):
if event.widget == self.winfo_toplevel() and \
self.bInCanvas(event.x, event.y):
self.yview_scroll(-event.delta, UNITS)
def onMouseWheelX(self, event):
if event.widget == self.winfo_toplevel() and \
self.bInCanvas(event.x, event.y):
self.xview_scroll(-event.delta, UNITS)
def bInCanvas(self, x, y):
if x > self.canvasFrame.winfo_x() and \
y > self.canvasFrame.winfo_y() and \
x < self.canvasFrame.winfo_x() + int(self.winfo_width())
and \
y < self.canvasFrame.winfo_y() + int(self.winfo_height()):
return True
return False


def test():
top = Frame()
top.pack(expand=YES, fill=BOTH)
sc = ScrolledCanvas(top, xscroll=True, yscroll=True, bg='Brown',
relief=SUNKEN)
sc.config(scrollregion=(0,0,1000, 1000))
sc.config(yscrollincrement=1)
sc.config(xscrollincrement=1)
sc.pack()

for i in range(10):
sc.create_text(150, 50+(i*100), text='spam'+str(i),
fill='beige')
top.mainloop()

if __name__ == '__main__':
test()
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top