I wanted to implement two finger scrolling in tkinter. Here is the result of my own attempt:
import tkinter as tk
class Scene:
def __init__(self, canvas):
self.canvas = canvas
self.elements = [
{
"type": "rect",
"x": canvas.winfo_width() / 2,
"y": canvas.winfo_height() / 2,
"width": 200,
"height": 200,
"color": (55 / 255, 55 / 255, 10 / 255),
},
{
"type": "rect",
"x": 100,
"y": 300,
"width": 200,
"height": 200,
"color": (155 / 255, 200 / 255, 10 / 255),
},
]
def update_scene(self, offset):
for element in self.elements:
element["x"] -= offset[0]
element["y"] -= offset[1]
self.render_scene()
def render_scene(self):
self.canvas.delete("all")
for element in self.elements:
if element["type"] == "rect":
self.canvas.create_rectangle(
element["x"],
element["y"],
element["x"] + element["width"],
element["y"] + element["height"],
fill=f"#{int(element['color'][0] * 255):02x}{int(element['color'][1] * 255):02x}{int(element['color'][2] * 255):02x}",
)
else:
print(f"Error: type {element['type']} is not supported.")
root = tk.Tk()
root.geometry("{}x{}".format(800, 600))
canvas = tk.Canvas(root)
canvas.pack(fill="both", expand=True)
canvas_scroll = [0, 0]
scene = Scene(canvas)
scene.render_scene()
def on_mouse_scroll(event):
canvas_scroll[0] = event.delta
canvas_scroll[1] = event.delta
scene.update_scene(canvas_scroll)
canvas.bind("<MouseWheel>", on_mouse_scroll)
root.mainloop()
The above only works in one diagonal/direction, instead of any direction (up, down, left, right, and all four diagonals)
The above was inspired by a Javascript snippet I found here: https://jsfiddle.net/qmyho24r/
I know using Shift-MouseWheel
works, but then I have to also press the shift key, instead of just using the trackpad and two fingers (like in the Javascript example).
How can I use two fingers scrolling in Tkinter?
tkinter does only support horizontal scrolling on windows from patchlevel 8.6.10 <=
I've created a small example that works for me with tkinter 8.6.12 on Win11.
When using two fingers with a little gap between them I can successfully scroll in both direction and move the View in a circle. I retrieve two different events depending on which direction I swap. This is also mentioned in the documentation.
import tkinter as tk
import sys
#https://stackoverflow.com/a/13874620/13629335
OS = sys.platform
def horizontal_scroll(event):
if OS in ('win32','darwin'):
canvas.xview_scroll(int(event.delta/120), 'units')
elif OS == 'linux':
if event.num == 5:
canvas.xview_scroll(-1, 'units')
elif event.num == 4:
canvas.xview_scroll(1, 'units')
def vertical_scroll(event):
if OS in ('win32','darwin'):
canvas.yview_scroll(int(event.delta/120), 'units')
elif OS == 'linux':
if event.num == 5:
canvas.yview_scroll(-1, 'units')
elif event.num == 4:
canvas.yview_scroll(1, 'units')
root = tk.Tk('test')
if int(root.tk.call("info", "patchlevel").split('.')[-1]) >= 10:
#https://docs.activestate.com/activetcl/8.6/get/relnotes/
canvas = tk.Canvas(root,highlightthickness=0,bd=0)
#something to show
v = viewsize = 150
cw = canvas.winfo_reqwidth()+v
ch = canvas.winfo_reqheight()+v/2
s = square = 50
canvas.create_rectangle(0,0, s,s, tags=('NW',))
canvas.create_rectangle(cw-s,0, cw,s, tags=('NE',))
canvas.create_rectangle(cw-s,ch-s, cw,ch, tags=('SE',))
canvas.create_rectangle(0,ch-s, s,ch, tags=('SW',))
canvas.pack(fill='both', expand=True, padx=10)
#update scrollregion
canvas.configure(scrollregion=canvas.bbox('all'))
#bindings
#https://stackoverflow.com/a/17457843/13629335
if OS in ('win32','darwin'):
#https://apple.stackexchange.com/q/392936
root.bind('<MouseWheel>', vertical_scroll)
root.bind('<Shift-MouseWheel>', horizontal_scroll)
if OS == 'linux':
#https://stackoverflow.com/a/17452217/13629335
root.bind('<Button-4>', vertical_scroll)
root.bind('<Button-5>', vertical_scroll)
root.bind('<Shift-Button-4>', horizontal_scroll)
root.bind('<Shift-Button-5>', horizontal_scroll)
root.mainloop()
else:
print('at least for windows it is supported at patchlevel 8.6.10')
root.destroy()