[Peter Lewerin] ([Peter Lewerin%|%content disclaimer%|%]) (2014-02-19) Many years ago on the page [A User's Guide to Tcl/Tk] someone mentioned the steps one would take using `[bindtags]` and `[bind]` to find out the bindings that apply to a window / widget and what action a particular binding indicates. [LV] asked for a tool that would automate investigating bindings, and I put together a basic browser as a suggestion. It was a bit of a kludge, with everything in global scope and so on, but it seemed to work. Today I decided to rewrite it and put it on a page of its own. My `[snit]` is quite rusty from being away from Tcl for so many years, so I may have made some mistakes. It does work however, and now everything is well-structured and encapsulated. ***Using the browser*** If you have a window / widget that you want to look into the bindings for, say a button (as in the original example): ====== pack [button .b -text {Example widget}] ====== Then you can instantiate a `bindingdisplay` Snit widget like this: ====== pack [bindingdisplay .bd -widget .b] ====== (In this case, the button widget and the bindingdisplay widget live side by side on `.`, but they do not have to, the bindingdisplay widget could have its own `[toplevel]` for instance.) This gives you a set of two scrolled listboxes (one listing bindtags, and one listing bindings) and a text label. The first listbox will have the items `.b`, `Button`, `.`, and `all`. Selecting `Button` fills the second listbox with six bindings, from `` to ``, that apply to the button via the `Button` class. Selecting `` sets the text label to display the text "tk::ButtonLeave %W". ***The `bindingdisplay` Snit widget*** You will of course have required the Snit package: ====== package require snit ====== This is how the bindingdisplay Snit widget is defined. It uses regular and tiled widgets, and another Snit widget that creates scrolled listboxes, which is defined under the next heading. It pre-fills the first listbox with bindtags information for the widget in question. It contains the methods to propagate the user's selections from bindtags to bindings to actions, and sets up the listboxes to perform them when a selection is made. ====== snit::widget bindingdisplay { option -widget {} component bindtags component bindings component actionframe component actionlabel delegate method setaction to actionlabel as {configure -text} constructor args { install bindtags using lister $win.c -text Bindtags install bindings using lister $win.b -text Bindings install actionframe using ttk::labelframe $win.f -text Action install actionlabel using ttk::label $win.f.a $self configurelist $args pack $actionlabel grid $bindtags $bindings grid $actionframe - -sticky w $bindtags fill {*}[bindtags [$self cget -widget]] $bindtags onselect [mymethod bindtagsToBindings] $bindings onselect [mymethod bindingsToAction] } method bindtagsToBindings {} { $self setaction {} $bindings fill {*}[bind [$bindtags get]] } method bindingsToAction {} { $self setaction [bind [$bindtags get] [$bindings get]] } } ====== ***The `lister` Snit widget*** This is a very basic scrolled listbox. It knows how to replace its contents with a new list of items, how to register actions to perform when an item is selected, and how to retrieve the latest selection made. ====== snit::widget lister { hulltype ttk::labelframe component listbox component scrollbar variable selection {} delegate option -text to hull constructor args { install listbox using tk::listbox $win.lbx -selectmode single -yscrollcommand [list $win.scr set] install scrollbar using ttk::scrollbar $win.scr -command [list $win.lbx yview] pack $listbox $scrollbar -side left -fill y $self configurelist $args } method fill args { $listbox delete 0 end $listbox insert end {*}$args } method onselect cmd { bind $listbox <> $cmd } method get {} { if {[$listbox curselection] ne {}} { set selection [$listbox get [$listbox curselection]] } set selection } } ====== ***The original code*** This was the code I posted back then. There are a lot of mistakes in it: I wrote it in a hurry. For one thing, it refers to the returned items from `bindtags` as "classes", even though only (in this case) `Button` is actually a class. ====== package require Tk set w [button .b] frame .classes label .classes.label -text {Classes} listbox .classes.box -selectmode single -yscrollcommand {.classes.scroller set} scrollbar .classes.scroller -command {.classes.box yview} pack .classes.label pack .classes.box .classes.scroller -side left -fill y frame .bindings label .bindings.label -text {Bindings} listbox .bindings.box -selectmode single -yscrollcommand {.bindings.scroller set} scrollbar .bindings.scroller -command {.bindings.box yview} pack .bindings.label pack .bindings.box .bindings.scroller -side left -fill y label .label -text {Action} label .action -textvariable action grid $w -sticky w grid .classes .bindings grid .label x -sticky w grid .action - -sticky w eval .classes.box insert end [bindtags $w] bind .classes.box <> { set ::class [.classes.box get [.classes.box curselection]] .bindings.box delete 0 end eval .bindings.box insert end [bind $::class] } bind .bindings.box <> { set ::action [string trim [bind $::class [.bindings.box get [.bindings.box curselection]]]] } ====== <>Widget | GUI | Snit | Snit Widgets | Introspection | Dev. Tools | Debugging