WJG March 16th 2005 - If scale widgets are crammed together or have a restricted area on screen then offering the user the option to enter numbers directly through the keyboard can be an advantage. This may be especially true if the user has some specific number in mind and dragging sliders can be, well, a drag. For those crafting a GUI with lots of sliders crammed into a tight space then this code snippet might be of use.
The code is pretty-simple and needs no clarification. Regarding the bindings, perform a simple Double-Button-1 click on the slider title and a entry field will appear displaying the current slider value. Pressing Return in the entry field or a further Double-Button-1 click on the title to restore the original scale widget.
User modifications might include deleting the Entry widget <Return> binding to offer the bare choice between input methods and provide additional variable handling code to allow doubles to be managed through the slider (it defaults to integers}.
package require Tk
proc newscale {w title variable from to} {
#define this proc first to prevent interpreter error
proc _[set w].ent {val} {
return [expr {[string is integer $val] || [string match {[-+]} $val]} ]
}
#create widget holder
frame $w -borderwidth 2 -relief ridge -height 10
label $w.lab -text $title -anchor w
pack $w.lab -side left
#alternative kb entry method
entry $w.ent -textvariable $variable -validate all -vcmd "_$w.ent %P"
#interactive slider with value
frame $w.fr2
label $w.fr2.lab -textvariable $variable -anchor w -width 3
pack $w.fr2.lab -side left
scale $w.fr2.sc -orient horizontal -borderwidth 1 \
-showvalue 0 -variable $variable \
-width 8 -sliderlength 10 \
-from $from -to $to
pack $w.fr2.sc -side left
pack $w.fr2 -side left
#bindings
bind $w.lab <Double-Button-1> {
if {[winfo ismapped [winfo parent %W].fr2.sc] } {
[winfo parent %W].ent delete 0 end
[winfo parent %W].ent insert 0 [[winfo parent %W].fr2.lab cget -text ]
pack [winfo parent %W].ent
focus [winfo parent %W].ent
pack forget [winfo parent %W].fr2
} else {
#set global variable value
pack [winfo parent %W].fr2
pack forget [winfo parent %W].ent -fill x
}
}
bind $w.ent <Return> {
pack forget %W
pack [winfo parent %W].fr2
}
}
proc demo {} {
set w .fr1
set ::v(1) -33
set ::v(2) 0
set ::v(3) 33
newscale .sc1 {Range1: } ::v(1) -100 100
newscale .sc2 {Range2: } ::v(2) -100 100
newscale .sc3 {Range3: } ::v(3) -100 100
pack .sc1 .sc2 .sc3 -side top
}
demo