Version 19 of spinbox

Updated 2007-02-15 12:14:20

http://purl.org/tcl/home/man/tcl8.4/TkCmd/spinbox.htm

So, what is a spinbox? It is a specialized entry widget, where you have a box displaying a value, and an up and down arrow that allows you to "click through" a series of values.

Here's an example:

 package require Tk 8.4

 set ::var 0.75
 proc myproc { } {
        puts "myproc: $::var"
 }

 spinbox .spin -from 0.00 -to 5.00 -increment 0.25 -format %5.2f -width 10 \
        -font 10 -justify center -textvariable var -command myproc

 pack .spin


LV: I'd really encourage people to place code that allows older versions of Tcl/Tk to have forward compatible functionality into tcllib and tklib - that way everyone benefits. Appropriate package info should keep it from kicking in inappropriately. - RS: Mmh, yeah, but that would involve "real" work (to fulfill the spinbox spec as much as possible), while I just quickly hacked this together in response to a c.l.t. post LV That's fine - if you notice, I'm not talking merely about the following code - I know that there has been work elsewhere on the wiki on forward compatibility; moving this type of code off of the wiki and into tcllib or tklib would enable more people to make use of it.


Pre-8.4 substitute: Here is a concoction of a 1-line high listbox with two tiny buttons, to approximate the effects of a spinbox:

 proc spinner {w args} {    
    set im(up) [image create bitmap -data "
 #define i_width 5
 #define i_height 3
 static char i_bits[] = {
    4,14,31
 }"]
 #---------- You can also have this C-like code more compact:
 set im(dn) [image create bitmap -data "
 #define i_width 5\n#define i_height 3\nstatic char i_bits[] = {\n31,14,4}"]

    frame $w
    eval listbox $w.l -height 1 $args    
    frame $w.f
    button $w.f.1 -image $im(up) -width 10 -height 4 \
          -command [list $w.l yview scroll -1 unit]
    button $w.f.2 -image $im(dn) -width 10 -height 4 \
          -command [list $w.l yview scroll 1 unit]
    pack $w.f.1 $w.f.2
    pack $w.l $w.f -side left -fill y
    return $w.l
 } ;# RS

#-------------------------------- Testing: http://mini.net/files/spinner.jpg

 set testlist {foo bar grill room}
 spinner .x -listvar testlist -bg yellow
 pack .x

Should you wonder how I got these little arrow images - then it's time for a little plug for strimj - string image routines, where the command

 strimj::xbm "@@@@@\n @@@ \n  @ "

delivers the XBM code for the down arrow (and the order of rows needed only to be reverted for the up arrow).


Still, the XBM specification looks ugly as sin (and disturbs indentation). Here's a little wrapper that hides the boring parts:

 proc xbmdata {width bytes} {
    set bytesperline [expr {($width+7) / 8}]
    set nbytes [llength [split $bytes ,]]
    set height [expr {$nbytes / $bytesperline}]
    set res    "#define i_width $width\n"
    append res "#define i_height $height\n"
    append res "static char i_bits[] = {\n$bytes}"
 } ;# RS

and in the spinner code you just write:

    set im(up) [image create bitmap -data [xbmdata 5 4,14,31]]
    set im(dn) [image create bitmap -data [xbmdata 5 31,14,4]]


[Explain not-well-documented-or-intuitive-to-many importance of -format in example:

    spinbox .s2 -from 0.0 -to 15.875 -increment 0.125 \
            -format %1.3f

]


This would be a good place for an explanation of the -command switch and editing the spinbox's entry. And possible workarounds. It is completely non-intuitive and causes a lot of lost time.

DRF- I use a bind to get around the editing of the entry problem:

    bind .spin <Leave> { puts [%W get] }

However, it would be nice to be able to execute the -command from within bind.


I've been playing with this code for some time... here's a spinbox menubutton implementation.


sbron- Until FRQ#1096323 is available the following code can be used to make a hexadecimal spinbox:

 # Command procedure for making a hexadecimal spinbox
 proc spinhex {w value direction format} {
     # Try to get the current hex value of the spinbox
     if {[scan $value %x newvalue] != 1} {set newvalue 0}

     # Calculate the new value
     if {$direction eq "up"} {
         if {$newvalue < round([$w cget -to])} {
             incr newvalue
         } elseif {[string is true [$w cget -wrap]]} {
             set newvalue [expr {round([$w cget -from])}]
         }
     } elseif {$direction eq "down"} {
         if {$newvalue > round([$w cget -from])} {
             incr newvalue -1
         } elseif {[string is true [$w cget -wrap]]} {
             set newvalue [expr {round([$w cget -to])}]
         }
     }

     # Set the spinbox to the new value
     $w set [format $format $newvalue]
 }

 # Create the spinbox. Set increment to 0 to disable the builtin button actions
 spinbox .spin -width 6 -from 0 -to 65535 -increment 0 -wrap true \
     -command {spinhex %W %s %d %%04X}

 # Initialize the spinbox value
 spinhex .spin 0 start %04X

Category Widget - Category Command - Category GUI - Tk syntax help - Arts and Crafts of Tcl-Tk Programming