The Preferences User Interface

   

Practical Programming in Tcl & Tk, Third Edition
By Brent B. Welch

Table of Contents
Chapter 42.  Managing User Preferences


The figure shows the interface for the items added with the Pref_Add command given in the previous section. The pop-up window with the extended help text appears after you click on "Scrollbar placement." The user interface to the preference settings is table-driven. As a result of all the Pref_Add calls, a single list of all the preference items is built. The interface is constructed by looping through this list and creating a user interface item for each:

Example 42-5 A user interface to the preference items.

graphics/42fig01.gif

 proc Pref_Dialog {} {    global pref    if [catch {toplevel .pref}] {       raise .pref    } else {       wm title .pref "Preferences"       set buttons [frame .pref.but -bd 5]       pack .pref.but -side top -fill x       button $buttons.quit -text Dismiss \          -command {PrefDismiss}       button $buttons.save -text Save \          -command {PrefSave}       button $buttons.reset -text Reset \          -command {PrefReset ; PrefDismiss}       label $buttons.label \          -text "Click labels for info on each item"       pack $buttons.label -side left -fill x       pack $buttons.quit $buttons.save $buttons.reset \          -side right -padx 4       frame .pref.b -borderwidth 2 -relief raised       pack .pref.b -fill both       set body [frame .pref.b.b -bd 10]       pack .pref.b.b -fill both       set maxWidth 0       foreach item $pref(items) {          set len [string length [PrefComment $item]]          if {$len > $maxWidth} {             set maxWidth $len          }       }       set pref(uid) 0       foreach item $pref(items) {          PrefDialogItem $body $item $maxWidth       }    } } 

The interface supports three different types of preference items: boolean, choice, and general value. A boolean is implemented with a checkbutton that is tied to the Tcl variable, which will get a value of either 0 or 1. A boolean is identified by a default value that is either ON or OFF. A choice item is implemented as a set of radiobuttons, one for each choice. A choice item is identified by a default value that is a list with the first element equal to CHOICE. The remaining list items are the choices, with the first one being the default choice. A regexp is used to check for CHOICE instead of using list operations. This is because Tcl 8.0 will complain if the value is not a proper list, which could happen with arbitrary values. If neither of these cases, boolean or choice, are detected, then an entry widget is created to hold the general value of the preference item:

Example 42-6 Interface objects for different preference types.
 proc PrefDialogItem { frame item width } {    global pref    incr pref(uid)    set f [frame $frame.p$pref(uid) -borderwidth 2]    pack $f -fill x    label $f.label -text [PrefComment $item] -width $width    bind $f.label <1> \       [list PrefItemHelp %X %Y [PrefHelp $item]]    pack $f.label -side left    set default [PrefDefault $item]    if {[regexp "^CHOICE " $default]} {       foreach choice [lreplace $default 0 0] {          incr pref(uid)          radiobutton $f.c$pref(uid) -text $choice \             -variable [PrefVar $item] -value $choice          pack $f.c$pref(uid) -side left       }    } else {       if {$default == "OFF" || $default == "ON"} {          # This is a boolean          set varName [PrefVar $item]          checkbutton $f.check -variable $varName \              -command [list PrefFixupBoolean $f.check $varName]          PrefFixupBoolean $f.check $varName          pack $f.check -side left       } else {          # This is a string or numeric          entry $f.entry -width 10 -relief sunken          pack $f.entry -side left -fill x -expand true          set pref(entry,[PrefVar $item]) $f.entry          set varName [PrefVar $item]          $f.entry insert 0 [uplevel #0 [list set $varName]]          bind $f.entry <Return> "PrefEntrySet %W $varName"       }    } } proc PrefFixupBoolean {check varname} {    upvar #0 $varname var    # Update the checkbutton text each time it changes    if {$var} {       $check config -text On    } else {       $check config -text Off    } } proc PrefEntrySet { entry varName } {    PrefValueSet $varName [$entry get] } 

graphics/tip_icon.gif

In this interface, when the user clicks a radiobutton or a checkbutton, the Tcl variable is set immediately. To obtain a similar effect with the general preference item, the <Return> key is bound to a procedure that sets the associated Tcl variable to the value from the entry widget. PrefEntrySet is a one-line procedure that saves us from using the more awkward binding shown below. Grouping with double quotes allows substitution of $varName, but then we must quote the square brackets to postpone command substitution:

 bind $f.entry <Return> "PrefValueSet $varName \[%W get\]" 

The binding on <Return> is done as opposed to using the -textvariable option because it interacts with traces on the variable a bit better. With trace you can arrange for a Tcl command to be executed when a variable is changed, as in Example 42-10 on page 592. For a general preference item it is better to wait until the complete value is entered before responding to its new value.

The other aspect of the user interface is the display of additional help information for each item. If there are lots of preference items, then there isn't enough room to display this information directly. Instead, clicking on the short description for each item brings up a toplevel with the help text for that item. The toplevel is marked transient so that the window manager does not decorate it:

Example 42-7 Displaying the help text for an item.
 proc PrefItemHelp { x y text } {    catch {destroy .prefitemhelp}    if {$text == {}} {       return    }    set self [toplevel .prefitemhelp -class Itemhelp]    wm title $self "Item help"    wm geometry $self +[expr $x+10]+[expr $y+10]    wm transient $self .pref    message $self.msg -text $text -aspect 1500    pack $self.msg    bind $self.msg <1> {PrefNukeItemHelp .prefitemhelp}    .pref.but.label configure -text \       "Click on pop-up or another label" } proc PrefNukeItemHelp { t } {    .pref.but.label configure -text \        "Click labels for info on each item"    destroy $t } 

       
    Top
     



    Practical Programming in Tcl and Tk
    Practical Programming in Tcl and Tk (4th Edition)
    ISBN: 0130385603
    EAN: 2147483647
    Year: 1999
    Pages: 478

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net