Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't the Python Tkinter Canvas Scroll?

Why can't I get the python tkinter canvas to respond to the vertical and horizontal swiping/scrolling of Apple's Magic Mouse? The scrollbars for the canvas work properly (meaning the horizontal bar works when I swipe/scroll horizontally on the mouse but not when I swipe/scroll vertically, and the vertical scrollbar moves when I swipe/scroll vertically but doesn't react to any horizontal swiping/scrolling motion), but the canvas doesn't react to any swiping/scrolling of the mouse.

Here is my example/test code:

from tkinter import *
import tkinter.ttk as ttk
from PIL import Image, ImageTk
root = Tk()

h = Scrollbar(root, orient=HORIZONTAL)
v = Scrollbar(root, orient=VERTICAL)
canvas = Canvas(root, scrollregion=(0, 0, 1000, 1000), yscrollcommand=v.set, xscrollcommand=h.set)
h['command'] = canvas.xview
v['command'] = canvas.yview
theImage = ImageTk.PhotoImage(Image.open('example.png')) #Assume a very large image
canvas.create_image(0,0,image=theImage, anchor='nw')
canvas.grid(column=0, row=0, sticky=(N,W,E,S))
h.grid(column=0, row=1, sticky=(W,E))
v.grid(column=1, row=0, sticky=(N,S))
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.mainloop()

I'm a total novice when it comes to both Python and tkinter, but I feel like this should be really simple and obvious (or at least do-able). And yet I've looked all over and still can't find the answer (though I might be searching using the wrong jargon).

What does it take to make the canvas react to scrolling/swiping inputs from the Magic Mouse like the scrollbars do already?

Edit: I'm using Python 3.4, Tkinter 8.5.18, Mac OS X 10.9.5, and an Apple Magic Mouse

like image 946
IntrepidArtisan Avatar asked Sep 27 '22 08:09

IntrepidArtisan


1 Answers

Assuming that the magic mouse's scroll and swipe inputs work like the scrolling regions on a standard trackpad, you need to bind the <MouseWheel> and <Shift-MouseWheel> events.

First the code, then some notes.

from tkinter import *
import tkinter.ttk as ttk
from PIL import Image, ImageTk

def on_vertical(event):
    canvas.yview_scroll(-1 * event.delta, 'units')

def on_horizontal(event):
    canvas.xview_scroll(-1 * event.delta, 'units')

root = Tk()
h = Scrollbar(root, orient=HORIZONTAL)
v = Scrollbar(root, orient=VERTICAL)
canvas = Canvas(root, scrollregion=(0, 0, 1000, 1000), yscrollcommand=v.set, xscrollcommand=h.set)
h['command'] = canvas.xview
v['command'] = canvas.yview
theImage = ImageTk.PhotoImage(Image.open('img'))
canvas.create_image(0,0,image=theImage, anchor='nw')
canvas.grid(column=0, row=0, sticky=(N,W,E,S))

canvas.bind_all('<MouseWheel>', on_vertical)
canvas.bind_all('<Shift-MouseWheel>', on_horizontal)

h.grid(column=0, row=1, sticky=(W,E))
v.grid(column=1, row=0, sticky=(N,S))
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.mainloop()

As you can see there are only 2 changes.

  1. There are two callback functions to handle the scroll events on_vertical and on_horizontal
  2. The canvas <MouseWheel> and <Shift-MouseWheel> events are bound to on_vertical and on_horizontal respectively.
like image 106
theB Avatar answered Sep 30 '22 06:09

theB