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?
CodePudding user response:
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()
Please feel free to share your experience for different platforms and to edit the code to take care of the dependencies.