Home > Mobile >  Tkinter - Scroll with mousepad / mouse gestures / two fingers scrolling in tkinter?
Tkinter - Scroll with mousepad / mouse gestures / two fingers scrolling in tkinter?

Time:01-30

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.

  • Related