# Commands Related to Mouse Wheel Event Handling

## For Scrollutil Version 1.5

### by

## Csaba Nemethi

## Contents

- The `scrollutil::addMouseWheelSupport` Command
- The `scrollutil::createWheelEventBindings` Command
- The `scrollutil::enableScrollingByWheel` Command
- The `scrollutil::adaptWheelEventHandling` Command
- The `scrollutil::setFocusCheckWindow` Command
- The `scrollutil::focusCheckWindow` Command

Start page

## The `scrollutil::addMouseWheelSupport` Command

NAME
  `scrollutil::addMouseWheelSupport` – Add mouse wheel support
SYNOPSIS

      scrollutil::addMouseWheelSupport tag ?axes?

REQUIRED TK VERSION
  8.4 or higher.
DESCRIPTION
  Adds mouse wheel support to the widgets having the specified binding tag by creating bindings for the mouse wheel events along the axes given by the optional `axes` argument, which must be `xy` (the default, meaning both the x and y axis), `x` (meaning the x axis only), or `y` (meaning the y axis only). The binding scripts created by this command will scroll the window given by the `%W` event field with the aid of the `xview scroll number units` and `yview scroll number units` subcommands of the associated Tcl command.
  REMARK 1: If `tag` is the path name of a window then the binding scripts created by this command are terminated by an invocation of the `break` command, in order to prevent the processing of the mouse wheel events by further binding scripts. For example, if `tag` is the path name of a text widget then the terminating `break` command makes sure that the mouse wheel events will not additionally be processed by the class bindings (associated with the binding tag `Text`), which in Tk 8.5 and later trigger a scrolling by pixels, unlike the bindings created by this command, which scroll the widget by units (i.e., lines and characters).
  REMARK 2: The canvas widget has no built-in bindings, but you can use this command to add mouse wheel support to the widget class `Canvas` or individual canvas widgets.
  REMARK 3: The mouse wheel events along the vertical axis are `<MouseWheel>` on Windows, `<MouseWheel>` and `<Option-MouseWheel>` on Mac OS X, and `<MouseWheel>`, `<Button-4>` and `<Button-5>` on X11 (where `<MouseWheel>` is not triggered by the X server, but can be produced using `event generate`). The mouse wheel events along the horizontal axis are `<Shift-MouseWheel>` on Windows, `<Shift-MouseWheel>` and `<Shift-Option-MouseWheel>` on Mac OS X, and `<Shift-MouseWheel>`, `<Shift-Button-4>` and `<Shift-Button-5>` on X11 (where `<Shift-MouseWheel>` is not triggered by the X server, but can be produced using `event generate`). On X11, when using Tk 8.7a3 or later, there are two more mouse wheel events along the horizontal axis: `<Button-6>` and `<Button-7>`, which are handled just like `<Shift-Button-4>` and `<Shift-Button-5>`, respectively. These events are commonly triggered by left/right tilting the scroll wheel of a mouse having one or two additional (thumb) buttons. (In Tk versions 8.6.x, with x >= 10, left/right tilting the scroll wheel of such a mouse gives rise to `<Shift-MouseWheel>` events on Windows and Mac OS X Aqua, and to `<Shift-Button-4>` and `<Shift-Button-5>` events on X11.)
KEYWORDS
  mouse wheel event, binding, scrolling

Contents Start page

## The `scrollutil::createWheelEventBindings` Command

NAME
  `scrollutil::createWheelEventBindings` – Create mouse wheel event bindings
SYNOPSIS

      scrollutil::createWheelEventBindings ?tag tag ...?

REQUIRED TK VERSION
  8.4 or higher on X11 and Mac OS X; 8.6b2 or later on Windows.
DESCRIPTION
  Creates mouse wheel event bindings for the specified binding tags such that if the widget under the pointer is (a descendant of) one of the scrollable widget containers having the same toplevel as the widget and registered via `scrollutil::enableScrollingByWheel` then these events will trigger a scrolling of that widget container. In case of several nested registered scrollable widget containers fulfilling these conditions the innermost one will be scrolled. Each `tag` argument must be `all` or the path name of an existing toplevel widget (including `.`).
  REMARK: The reason for restricting the `tag` arguments to `all` and path names of existing toplevel widgets rather than supporting also tags like `"Scrollableframe"` (for scrollutil::scrollableframe), `"BwScrollableFrame"` (for BWidget ScrollableFrame) or `"Scrolledframe"` (for iwidgets::scrolledframe) is that the mouse wheel events should trigger a scrolling of the widget container under the pointer not only if the widget under the pointer is the widget container itself but also if it is a descendant of the latter (recall that for each window, the path name of its nearest toplevel ancestor and the tag `all` are contained in the window's default list of binding tags).
KEYWORDS
  mouse wheel event, binding, scrolling, scrollable widget container

Contents Start page

## The `scrollutil::enableScrollingByWheel` Command

NAME
  `scrollutil::enableScrollingByWheel` – Register scrollable widget containers for scrolling by the mouse wheel
SYNOPSIS

      scrollutil::enableScrollingByWheel ?scrollableWidgetContainer scrollableWidgetContainer ...?

REQUIRED TK VERSION
  8.4 or higher on X11 and Mac OS X; 8.6b2 or later on Windows.
DESCRIPTION
  Adds the specified scrollable widget containers to the internal list of widget containers that are registered for scrolling by the mouse wheel event bindings created by the `scrollutil::createWheelEventBindings` command.
  REMARK: When a scrollable widget container whose path name was passed to this command gets destroyed, it is automatically removed from the above-mentioned internal list of registered widget containers.
KEYWORDS
  mouse wheel event, binding, scrolling, scrollable widget container

Contents Start page

## The `scrollutil::adaptWheelEventHandling` Command

NAME
  `scrollutil::adaptWheelEventHandling` – Adapt mouse wheel event handling
SYNOPSIS

      scrollutil::adaptWheelEventHandling ?widget widget ...?

REQUIRED TK VERSION
  8.4 or higher on X11 and Mac OS X; 8.6b2 or later on Windows.
DESCRIPTION
  For each `widget` argument, the command performs the following actions:
  - If `widget` is the path name of a tablelist widget then it sets the latter's `-xmousewheelwindow` and `-ymousewheelwindow` options to the path name of the containing toplevel window, provided that the Tablelist version is 6.4 or later (for earlier Tablelist versions the command silently ignores any tablelist widget passed to it as argument). As a result, a mouse wheel event over the tablelist's body or edit window (more precisely, a mouse wheel event sent to any component of the tablelist having the binding tag `TablelistBody` or `TablelistEdit`) will be handled as follows:
    - If the focus is inside the tablelist widget then the event will scroll the tablelist or its edit window and no further processing of the event will take place.
    - If the focus is outside the tablelist widget then no scrolling of the tablelist's body or edit window will happen. Instead, the event will be redirected to the containing toplevel window via `event generate`. This in turn will trigger a scrolling of the (innermost) widget container that is an ancestor of `widget` and has the same toplevel (if there is such a scrollable widget container), provided that the path name of the containing toplevel widget or the binding tag `all` was passed to the `scrollutil::createWheelEventBindings` command and this widget container was registered for scrolling via `scrollutil::enableScrollingByWheel`.
  - Otherwise it locates the (first) binding tag that has mouse wheel event bindings and is different from both the path name of the containing toplevel window and `all`. If the search for this tag was successful then the command modifies the widget's list of binding tags by prepending the tag `WheeleventRedir` and appending the tag `WheeleventBreak` to this binding tag. As a result, a mouse wheel event sent to this widget will be handled as follows:
    - If the focus is on or inside the window `[focusCheckWindow widget]` then the event will be handled by the binding script associated with this tag and no further processing of the event will take place.
    - If the focus is outside the window `[focusCheckWindow widget]` then the event will be redirected to the containing toplevel window via `event generate` rather than being handled by the binding script associated with the above-mentioned tag. This in turn will trigger a scrolling of the (innermost) widget container that is an ancestor of `widget` and has the same toplevel (if there is such a scrollable widget container), provided that the path name of the containing toplevel widget or the binding tag `all` was passed to the `scrollutil::createWheelEventBindings` command and this widget container was registered for scrolling via `scrollutil::enableScrollingByWheel`.
  REMARK 1: This command is designed to be invoked for widgets that have mouse wheel event bindings and are descendants of a scrollable widget container (although it does no harm if it is called for other widgets, too). The Tk and tile widgets having class bindings for mouse wheel events are: listbox, text, Tk core scrollbar, ttk::scrollbar, ttk::combobox, ttk::spinbox, and ttk::treeview. Examples of widgets with binding tags other than their class names that have mouse wheel event bindings are tablelist widgets as well as the entry components of mentry widgets of type `"Date"`, `"Time"`, `"DateTime"`, `"IPAddr"`, and `"IPv6Addr"` (for Mentry versions 3.2 and above).
  REMARK 2: The mouse wheel event class bindings for the Tk core scrollbar on Windows and X11 were added in Tk 8.6. Prior to this Tk version there were such bindings only for the windowing systems `classic` and `aqua` on the Macintosh. Scrollutil eliminates this discrepancy by automatically creating the `Scrollbar` class bindings for mouse wheel events on Windows and X11. Note also that the ttk::scrollbar widget has no built-in class bindings for mouse wheel events, but Scrollutil automatically creates the missing bindings by copying the mouse wheel event bindings of the widget class `Scrollbar` to the binding tag `TScrollbar`.
  REMARK 3: As mentioned above, Tk core scrollbar and ttk::scrollbar widgets have class bindings for mouse wheel events, hence this command should be invoked for them in case they are descendants of a scrollable widget container. Since this task can become tedious, Scrollutil makes sure that if you pass a widget to this command and that widget is embedded into a scrollarea via the latter's `setwidget` subcommand, then this command will automatically be invoked for the scrollbars of that scrollarea, too.
  REMARK 4: When handling a mouse wheel event sent to a Tk core or tile scrollbar whose path name was passed to this command, if the focus is on or inside the associated widget then the event will be processed by the scrollbar rather than being redirected to the containing toplevel, just as if the focus were on the scrollbar itself.
  REMARK 5: Invoking this command for widgets that have mouse wheel event bindings and are descendants of a scrollable widget container is essential for a user-friendly mouse wheel event handling in scrollable widget containers. Without this step the mouse wheel events would scroll both the listbox, text, ttk::treeview, or tablelist widget under the pointer and the widget container to whose descendants the latter belongs, or they would select the next/previous value in the ttk::combobox or ttk::spinbox under the pointer in addition to scrolling the widget container. After invoking this command, e.g, for a listbox within a scrollable widget container, the mouse wheel events over that widget will only scroll the listbox if it has the focus. Likewise, after invoking this command for a ttk::combobox or ttk::spinbox within a scrollable widget container, the mouse wheel events over that widget will only select its next/previous value if it has the focus. In both examples, if the focus is outside the widget in question then the mouse wheel events will scroll the widget container instead.
KEYWORDS
  mouse wheel event, binding, event handling, scrolling, scrollable widget container, focus

Contents Start page

## The `scrollutil::setFocusCheckWindow` Command

NAME
  `scrollutil::setFocusCheckWindow` – Set the "focus check window"
SYNOPSIS

      scrollutil::setFocusCheckWindow widget ?widget ...? otherWidget

REQUIRED TK VERSION
  8.4 or higher on X11 and Mac OS X; 8.6b2 or later on Windows.
DESCRIPTION
  For each `widget` argument, the command sets the associated "focus check window" to `otherWidget`. This is the window to be used in the binding scripts for the tag `WheeleventRedir` instead of the widget when checking whether the focus is on/inside or outside that window. For each `widget` argument, `otherWidget` must be an ancestor of or identical to `widget`.
  REMARK 1: When a widget whose path name was passed to this command as one of its `widget` arguments gets destroyed, the association between the widget and its "focus check window" is automatically removed.
  REMARK 2: This command comes in handy if for some widgets you want to make the focus check within the binding scripts for the tag `WheeleventRedir` less restrictive. For example, if the widget under the pointer is an entry component of a mentry `me` of type `"Date"`, `"Time"`, `"DateTime"`, `"IPAddr"`, or `"IPv6Addr"` and the focus is on any of its siblings, then the mouse wheel events sent to this entry should be handled by the entry widget itself rather than scrolling the widget container that is an ascendant of the mentry. You can achieve this by invoking

  >     set entryList [$me entries]
  >     eval scrollutil::adaptWheelEventHandling $entryList
  >     eval scrollutil::setFocusCheckWindow     $entryList [list $me]

  With Tcl/Tk 8.5 or above, you can use the more compact form

  >     set entryList [$me entries]
  >     scrollutil::adaptWheelEventHandling {*}$entryList
  >     scrollutil::setFocusCheckWindow     {*}$entryList $me

  REMARK 3: As a similar example, suppose that `ss` is a scrollsync widget that was populated via its `setwidgets` subcommand with child widgets. Then, if the widget under the pointer is one of these children and the focus is on any of the other children passed to that subcommand, then the mouse wheel events sent to the child under the pointer should be handled by that child widget itself rather than scrolling the widget container that is an ascendant of the scrollsync. You can achieve this with the following code:

  >     set widgetList [$ss widgets]
  >     eval scrollutil::adaptWheelEventHandling $widgetList
  >     eval scrollutil::setFocusCheckWindow     $widgetList [list $ss]

  Again, with Tcl/Tk 8.5 or above, you can use the more compact form

  >     set widgetList [$ss widgets]
  >     scrollutil::adaptWheelEventHandling {*}$widgetList
  >     scrollutil::setFocusCheckWindow     {*}$widgetList $ss

KEYWORDS
  binding, focus, "focus check window"

Contents Start page

## The `scrollutil::focusCheckWindow` Command

NAME
  `scrollutil::focusCheckWindow` – Query the "focus check window"
SYNOPSIS

      scrollutil::focusCheckWindow widget

REQUIRED TK VERSION
  8.4 or higher on X11 and Mac OS X; 8.6b2 or later on Windows.
DESCRIPTION
  Returns the path name of the "focus check window" associated with the `widget` argument. This is the window that is used in the binding scripts for the tag `WheeleventRedir` instead of the widget when checking whether the focus is on/inside or outside that window. If the command `scrollutil::setFocusCheckWindow` was not invoked for `widget` then the return value is `widget` itself.
KEYWORDS
  binding, focus, "focus check window"

Contents Start page