Change Default <MouseWheel> Bindings BehaviorJeff HobbsKeith Vetter$Revision: 1.11 $
This TIP proposes changing the default <MouseWheel> bindings in Tk to have "better" behaved defaults for a larger set of applications.
The existing <MouseWheel> bindings only operate on a small handful of widgets, and only when they have focus. This essentially means that only the text widget ever has useful <MouseWheel> behavior. This is not how the majority of applications wish to use the MouseWheel. They operate primarily on a mouse-focus model (scroll what the mouse is over, not what has focus). In addition, <Shift-MouseWheel> horizontal scrolling support is added.
The bindings changes are very simply these:
cHJvYyA6OnRrOjpNb3VzZVdoZWVsIHt3RmlyZWQgWCBZIEQge3NoaWZ0ZWQgMH19IHs=ICAgICMgU2V0IGV2ZW50IHRvIGNoZWNrIGJhc2VkIG9uIGNhbGw=ICAgIHNldCBldnQgIjxbZXhwciB7JHNoaWZ0ZWQ/e1NoaWZ0LX06e319XU1vdXNlV2hlZWw+Ig==ICAgICMgZG8gbm90IGRvdWJsZS1maXJlIGluIGNhc2UgdGhlIGNsYXNzIGFscmVhZHkgaGFzIGEgYmluZGluZw==ICAgIGlmIHtbYmluZCBbd2luZm8gY2xhc3MgJHdGaXJlZF0gJGV2dF0gbmUgIiJ9IHsgcmV0dXJuIH0=ICAgICMgb2J0YWluIHRoZSB3aW5kb3cgdGhlIG1vdXNlIGlzIG92ZXI=ICAgIHNldCB3IFt3aW5mbyBjb250YWluaW5nICRYICRZXQ==ICAgICMgaWYgd2UgYXJlIG91dHNpZGUgdGhlIGFwcCwgdHJ5IGFuZCBzY3JvbGwgdGhlIGZvY3VzIHdpZGdldA==ICAgIGlmIHshW3dpbmZvIGV4aXN0cyAkd119IHsgY2F0Y2gge3NldCB3IFtmb2N1c119IH0=ICAgIGlmIHtbd2luZm8gZXhpc3RzICR3XX0gew==CWlmIHtbYmluZCAkdyAkZXZ0XSBuZSAiIn0gew==CSAgICAjIEF3a3dhcmQgLi4uIHRoaXMgd2lkZ2V0IGhhcyBhIE1vdXNlV2hlZWwgYmluZGluZywgYnV0IHRvCSAgICAjIHRyaWdnZXIgc3VjY2Vzc2Z1bGx5IGluIGl0LCB3ZSBtdXN0IGdpdmUgaXQgZm9jdXMuCSAgICBjYXRjaCB7Zm9jdXN9IG9sZA==CSAgICBpZiB7JHcgbmUgJG9sZH0geyBmb2N1cyAkdyB9CSAgICBldmVudCBnZW5lcmF0ZSAkdyAkZXZ0IC1yb290eCAkWCAtcm9vdHkgJFkgLWRlbHRhICRECSAgICBpZiB7JHcgbmUgJG9sZH0geyBmb2N1cyAkb2xkIH0=CSAgICByZXR1cm4=CX0=CSMgYXF1YSBhbmQgeDExL3dpbjMyIGhhdmUgZGlmZmVyZW50IGRlbHRhIGhhbmRsaW5nCWlmIHtbdGsgd2luZG93aW5nc3lzdGVtXSBuZSAiYXF1YSJ9IHs=CSAgICBzZXQgZGVsdGEgW2V4cHIgey0gKCREIC8gMzApfV0=CX0gZWxzZSB7CSAgICBzZXQgZGVsdGEgW2V4cHIgey0gKCREKX1dCX0=CSMgc2Nyb2xsYmFycyBoYXZlIGRpZmZlcmVudCBjYWxsIGNvbnZlbnRpb25zCWlmIHtbc3RyaW5nIG1hdGNoICIqU2Nyb2xsYmFyIiBbd2luZm8gY2xhc3MgJHddXX0gew==CSAgICBjYXRjaCB7dGs6OlNjcm9sbEJ5VW5pdHMgJHcgXA==CQkgICAgICAgW3N0cmluZyBpbmRleCBbJHcgY2dldCAtb3JpZW50XSAwXSAkZGVsdGF9CX0gZWxzZSB7CSAgICBzZXQgY21kIFtsaXN0ICR3IFtleHByIHskc2hpZnRlZCA/ICJ4dmlldyIgOiAieXZpZXcifV0gXA==CQkJIHNjcm9sbCAkZGVsdGEgdW5pdHNdCSAgICAjIFdhbGtpbmcgdXAgdG8gZmluZCB0aGUgcHJvcGVyIHdpZGdldCBoYW5kbGVzIGNhc2VzIGxpa2U=CSAgICAjIGVtYmVkZGVkIHdpZGdldHMgaW4gYSBjYW52YXM=CSAgICB3aGlsZSB7W2NhdGNoICRjbWRdICYmIFt3aW5mbyB0b3BsZXZlbCAkd10gbmUgJHd9IHs=CQlzZXQgdyBbd2luZm8gcGFyZW50ICR3XQ==CSAgICB9CX0=ICAgIH0=fQ==YmluZCBhbGwgPE1vdXNlV2hlZWw+IFtsaXN0IDo6dGs6Ok1vdXNlV2hlZWwgJVcgJVggJVkgJUQgMF0=YmluZCBhbGwgPFNoaWZ0LU1vdXNlV2hlZWw+IFtsaXN0IDo6dGs6Ok1vdXNlV2hlZWwgJVcgJVggJVkgJUQgMV0=aWYge1t0ayB3aW5kb3dpbmdzeXN0ZW1dIGVxICJ4MTEifSB7ICAgICMgU3VwcG9ydCBmb3IgbW91c2V3aGVlbHMgb24gTGludXgvVW5peCBjb21tb25seSBjb21lcyB0aHJvdWdoICAgICMgbWFwcGluZyB0aGUgd2hlZWwgdG8gdGhlIGV4dGVuZGVkIGJ1dHRvbnMuICAgIGJpbmQgYWxsIDw0PiBbbGlzdCA6OnRrOjpNb3VzZVdoZWVsICVXICVYICVZIDEyMF0=ICAgIGJpbmQgYWxsIDw1PiBbbGlzdCA6OnRrOjpNb3VzZVdoZWVsICVXICVYICVZIC0xMjBdfQ==
Instead of requiring a widget to have focus to receive MouseWheel events, the new proposal operates with MouseWheel as a global binding. When fired, it first does a safety check to prevent double-firing if an existing MouseWheel binding is on the widget. It then finds the widget which the mouse if over and uses that as the target for the scrolling event. If that widget doesn't exist (usually meaning that it returned {} indicating we are outside the Tk app), then use the widget which has the actual focus.
In scrolling, the scrollbar must be treated separately, since it has its own calling conventions. All others widgets get called with the standard yview scroll command, caught in case of errors, which are ignored.
This has been discussed on the tcl-mac mailing list already as the desired behavior, and confirmed to be more intuitive on Windows as well. The above code is already in use by applications that use widget extensions and megawidgets such as BWidgets without any adverse effects seen. Note that the existing MouseWheel bindings must first be removed, using the following code:
c2V0IG13X2NsYXNzZXMgW2xpc3QgVGV4dCBMaXN0Ym94IFRhYmxlIFRyZWVDdHJsXQ==Zm9yZWFjaCBjbGFzcyAkbXdfY2xhc3NlcyB7IGJpbmQgJGNsYXNzIDxNb3VzZVdoZWVsPiB7fSB9aWYge1t0ayB3aW5kb3dpbmdzeXN0ZW1dIGVxICJ4MTEifSB7ICAgIGZvcmVhY2ggY2xhc3MgJG13X2NsYXNzZXMgew==CSBiaW5kICRjbGFzcyA8ND4ge30=CSBiaW5kICRjbGFzcyA8NT4ge30=ICAgIH0=fQ==
Shift-MouseWheel was added after initial discussion.
Use of "*Scrollbar" is to catch TScrollbar as well.
This is adapted from tklib/style/as.tcl mousewheel adjustments and has proved useful and workable across a variety of applications.
There is a bit of awkwardness in handling widgets that have their own MouseWheel bindings in that core Tk requires these have focus to receive the event. It may be better to fix this forced limitation in Tk rather than the special-case code above (although that code does work).
This document has been placed in the public domain.