Using the Mouse Wheel with Tkinter (Python)

vegaseat 0 Tallied Votes 22K Views Share

This short Python snippet shows you how to read mouse wheel events with the Tkinter GUI toolkit. Windows and Linux have different bindings and read different events, but can be included in the same program code for use with either operating system.

# explore the mouse wheel with the Tkinter GUI toolkit
# Windows and Linux generate different events
# tested with Python25

import Tkinter as tk

def mouse_wheel(event):
    global count
    # respond to Linux or Windows wheel event
    if event.num == 5 or event.delta == -120:
        count -= 1
    if event.num == 4 or event.delta == 120:
        count += 1
    label['text'] = count

count = 0
root = tk.Tk()
root.title('turn mouse wheel')
root['bg'] = 'darkgreen'

# with Windows OS
root.bind("<MouseWheel>", mouse_wheel)
# with Linux OS
root.bind("<Button-4>", mouse_wheel)
root.bind("<Button-5>", mouse_wheel)

label = tk.Label(root, font=('courier', 18, 'bold'), width=10)
label.pack(padx=40, pady=40)

root.mainloop()

Dani AI

Generated

Cross-platform mouse wheel handling in Tkinter is mostly about normalizing events. Windows and macOS send <MouseWheel> with event.delta (sign indicates direction; magnitude varies). On many Linux/X11 setups there is no <MouseWheel>; scroll up/down arrive as <Button-4> and <Button-5>. Also note that some Tk builds deliver wheel events to the focused widget rather than the one under the pointer. If scrolling seems dead, set focus on pointer enter.

A small pattern you can drop into apps is to bind both styles and normalize deltas before calling yview_scroll or xview_scroll:

import sys
import tkinter as tk

def wheel_units(event):
    # Normalize to unit steps: +1 for up, -1 for down
    if hasattr(event, "delta") and event.delta:
        # Windows usually multiples of 120; macOS often small ints
        d = event.delta
        if sys.platform.startswith("win"):
            d = int(d / 120) if d % 120 == 0 else int(d / 120) or (1 if d > 0 else -1)
        return 1 if d > 0 else -1
    # X11 uses Button-4/5 for vertical wheel
    return 1 if getattr(event, "num", 0) == 4 else -1

def bind_wheel(widget, y_target=None, x_target=None):
    y_target = y_target or widget
    x_target = x_target or widget
    widget.bind("<Enter>", lambda e: widget.focus_set())
    widget.bind("<MouseWheel>", lambda e: y_target.yview_scroll(-wheel_units(e), "units"))
    widget.bind("<Shift-MouseWheel>", lambda e: x_target.xview_scroll(-wheel_units(e), "units"))
    widget.bind("<Button-4>", lambda e: y_target.yview_scroll(-1, "units"))
    widget.bind("<Button-5>", lambda e: y_target.yview_scroll(1, "units"))

Tips:

  • For horizontal wheels on X11, some systems emit <Button-6>/<Button-7>; bind those if needed.
  • Bind to the specific scrollable widget (e.g., Text, Canvas, Listbox) rather than bind_all to avoid hijacking the wheel globally.

References:

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.