TIP 474: Treat the mouse wheel events in a uniform way

Author:	Arjen Markus <[email protected]>
Author:	Jan Nijtmans <[email protected]>
State:	Final
Type:	Project
Vote:           Done
Vote-Summary:   Accepted 7/0/2
Votes-For:      BG, DKF, FV, JN, KW, MC, SL
Votes-Against:  none
Votes-Present:  DGP, KBK
Created:	25-Aug-2017
Post-history:	PM
Tcl-Version:	8.7
Keywords:	Tk, events
Tk-Branch:	tip474


This TIP proposes to treat the mouse wheel events on all platforms in the same way. Currently, a program running on Windows binds to "MouseWheel" events, whereas a program running on Linux binds to "ButtonPress-4" and "ButtonPress-5" commands. This makes it somewhat awkward to support both types of platforms having identical behaviour.


Tk provides a means to define user-interfaces using code that is almost perfectly independent of the platform that the program should run on. It therefore makes sense that the treatment of user actions, such as mouse clicks and the use of the mouse wheel should be independent of the platform as well. Currently, however, "Windows-type" and OSX platforms support the "MouseWheel" event, whereas for "Linux-type" platforms the program binds to "ButtonPress-4" and "ButtonPress-5" events. This is in contrast to almost all other events and event bindings.

The documentation in its present form only describes the "MouseWheel" form.

Current behaviour

The code fragment below illustrates the behaviour: run it under various platforms and use the mouse wheel in the canvas window to see which bindings fired.

pack [canvas .c]

catch {console show}

bind .c <Button> [list puts "Button %W %b"]
bind .c <Shift-Button> [list puts "Shift-Button %W %b"]
bind .c <Control-Button> [list puts "Control-Button %W %b"]
bind .c <MouseWheel> [list puts "MouseWheel %W %D"]
bind .c <Shift-MouseWheel> [list puts "Shift-MouseWheel %W %D"]
bind .c <Control-MouseWheel> [list puts "Control-MouseWheel %W %D"]


This TIP proposes to extend the bindings for the mouse wheel in such a way that it does not matter which platform the program runs on. On X11, the "Button 4" up to "Button 7" events will be translated internally to equivalent "MouseWheel" events. The modifiers "Option" and "Shift" will be supported analogously.

The "xview scroll" and "yview scroll" commands are modified to accept floats in stead of integers. This doesn't mean that we can scroll for 0.5 units or pages now, the numbers are rounded up when positive and rounded down when negative. So ".w yview scroll -0.1 units" will have the same effect as ".w yview scroll -1 units". This way, the bindings don't have to do this special rounding any more, as they are doing now.

A new helper function tk::MouseWheel is implemented. The disadvantage of the current bindings is that the expr expression needs to be parsed for every mouse move. The tk::MouseWheel function contains the same expression, but is compiled only once. So, this is purely an optimization. With that, the text widget bindings become:

bind Text <MouseWheel> {
    tk::MouseWheel %W y %D -3.0 pixels
bind Text <Option-MouseWheel> {
    tk::MouseWheel %W y %D -0.3 pixels
bind Text <Shift-MouseWheel> {
    tk::MouseWheel %W x %D -3.0 pixels
bind Text <Shift-Option-MouseWheel> {
    tk::MouseWheel %W x %D -0.3 pixels

On all platforms, button 1 will be the left mouse button, button 2 the middle mouse button and button 3 the right mouse button. In Tk 8.6 and earlier, MacOS always defined buttons 2 and 3 differently. In Tk 8.7, Tk will do the swapping for us.

Considerations regarding the incompatibility

The physical buttons 4 up to 9 on Windows or MacOS, will be translated to X11 buttons 8 up to 13. From the script level nothing changes: The buttons still can be accessed from scripts as being buttons 4 up to 9. This means that X11 buttons 4 to 7 are not accessible through script any more, the only way to access those are through the translated MouseWheel events. On X11, buttons 4 up to 9 in scripts will handle the X11 buttons numbered 8 up to 13.

On macOS, the scaling for MouseWheel buttons has always been different from those on Windows, with a factor of 120. This means that applications assuming Tk 8.6 <MouseWheel> events will need to be modified to the new behaviour, otherwise the screen movements will be far too much. On Windows, everything works as before, no incompatibility there. Many applications already define the <MouseWheel> binding on X11, even though in Tk 8.6 they are not used. Such applications will work on X11 in Tk 8.7 the same as in Tk 8.6

If the application needs to support Tcl/Tk 8.6, an extra check is required to decide which events to listen to. An example can be found in the "cscroll" demo.

This seems a minor inconvenience for gaining further platform-independence.

Reference Implementation

In Tk branch tip474.


This document is placed in public domain.