bind .t.c <MouseWheel> {%W yview scroll [expr {-%D/120}] units}Dividing by 120 leads to scrolling one line per wheel click (minimum effective wheel movement) - use a smaller divisor if you want to scroll faster. (RS)By "cubing" the number of units, you have the effect that slow turning of the wheel moves slowly, while fast turning lets you jump up or down:
bind .t.c <MouseWheel> {%W yview scroll [expr {int(pow(%D/-120,3))}] units}Kevin Walzer On OS X/Aqua the correct mousewheel binding would be:
bind .t.c <MouseWheel> {%W yview scroll [expr {- (%D)}] units}PAK This didn't work on my Windows 2000 box with Tcl 8.4. Instead I accumulated all MouseWheel events for 200 ms before cubing. E.g.,
bind .t.c <MouseWheel> { collect %W %D } set ::afterid {} set ::delta 0 proc collect {W D} { global delta global afterid if {$afterid eq {}} { set delta $D set afterid [after 200 "$W yview scroll \[expr {int(pow(\$delta/-120,3))}] units"] } else { incr delta $D } }This will also work on Unix with the Button-4/Button-5 to MouseWheel translation given below.
rmax AFAIK, <MouseWheel> works on Windows only. On X you have to bind to the <Button-4> and <Button-5> events. - IIRC, Button-4/5 is even not the only way of mapping the mouse wheel on X. As X doesn't support mouse wheels natively, there are at least three different possible mappings floating around, but I don't currently tremember the other two.ZB 2007-10-09 I'm using (8.5b1 on Linux) something like this - and it just works:
bind .win <MouseWheel> "MouseScroll %D"
KBK Note that on Windows, the <MouseWheel> events don't go to the window that contains the mouse pointer, but rather the window that has the keyboard focus. For various arcane reasons, this behavior is The Right Thing, but it surprises most programmers the first time they see it. Also, note that directing the <MouseWheel> events to the window with the focus means that the window that is to be scrolled must be able to take the focus.PAK If you insist on doing The Wrong Thing, you can do so by binding the toplevel window to the <MouseWheel> event then trigger a virtual event <<Wheel>> with the correct window. Because you can't set -delta for virtual events, you will need to save the delta value in a global variable which you can recover in the wheel binding.
bind [winfo toplevel .t.graph] <MouseWheel> { trigger %W %X %Y %D } proc trigger {W X Y D} { set w [winfo containing -displayof $W $X $Y] if { $w ne "" } { set x [expr {$X-[winfo rootx $w]}] set y [expr {$Y-[winfo rooty $w]}] global delta set delta $D event generate $w <<Wheel>> -rootx $X -rooty $Y -x $x -y $y } } bind .t.graph <<Wheel>> { %W zoom %x %y $delta }KPV Tip 171 [1] proposes to change <MouseWheel> events from being sent to the focus window to the window containing the mouse. This is actually how BWidgets has been doing it all along. I find that this is more intuitive and is The Right Thing.
Font resizing via mousewheel: The following binding reconfigures a widget with -font attribute (e.g. text, message, entry ...) according to mousewheel rotation:
pack [text .t -font {Helvetica 10} -wrap word -width 30 -height 10] .t insert end "This is a little demo text to test the font sizing via mousewheel" catch {bind .t <MouseWheel> { set font [%W cget -font] set fs [expr {[lindex $font 1]+%D/120}] %W config -font [lreplace $font 1 1 $fs] }}I've added the catch because on older Windows versions this event is not supported. Also, the default font does not scale in fine steps - but by specifying one that is implemented as TrueType, the effect is really nice ;-) RS
MGS Here's a quick little hack to get MouseWheel events on X (Linux):
bind all <Button-4> \ {event generate [focus -displayof %W] <MouseWheel> -delta 120} bind all <Button-5> \ {event generate [focus -displayof %W] <MouseWheel> -delta -120}Then you could do (for instance):
bind Scrollbar <MouseWheel> {eval [%W cget -command] scroll [expr {%D/-120}] units}but this won't work (as it is) for scrollbars with no -command set. RS: Then again, a scrollbar without -command is a pretty useless creature...
RWC Some links to other MouseWheel code:
- http://colas.nahaboo.net/mouse-wheel-scroll/#tcl
- Supporting mouse wheel on vertical scrollbars (ActiveState Cookbook)
RS 2007-09-24: I'm not sure how the state of discussion is about mousewheel enabling by just mousing-over, but I wanted this for a UI with a listbox and a text widget, both scrollable. Simple but useful:
foreach i {.listbox .text} {bind $i <Enter> {focus %W}}MG has added this binding to one of his apps, which has a lot of textwidgets, for handling mousewheel events (requires Tcl 8.5):
bind Text <MouseWheel> {} bind all <MouseWheel> [list mouseWheel %W %D] proc mouseWheel {widget delta} { if { $delta >= 0 } { set cmd [list yview scroll [expr {-$delta/3}] pixels] } else { set cmd [list yview scroll [expr {(2-$delta)/3}] pixels] } set over [winfo containing -displayof $widget {*}[winfo pointerxy $widget]] if { $over == "" || [catch {$over {*}$cmd}] } { catch {$widget {*}$cmd} } return; };# mouseWheelIt attempts to scroll the widget the mouse is over first, and then tries the one with the focus (where the event was actually generated) if it fails.
<MouseWheel> in TCL 8.6
HaO 2012-03-08: Koen Danckaert enlighted me in the MouseWheel implementation in Tcl 8.6 by a clt post of today titled "MouseWheel TIP #171 interaction with canvas" [2] .Here you are another implementation for the mousewheel: making a scale scrolled by mousewheel
scale .s -orient horizontal -from 0 -to 100 pack .s bind Scale <Enter> {focus %W} ; # focus on the scale when mouse comes over it bind Scale <Leave> {focus .} ; # focus out the scale bind Scale <MouseWheel> {set increment [expr (%D/120)]; if {$increment == 1} {event generate %W <Left>} else {event generate %W <Right>} }