Version 0 of Building User Interfaces with Tcl and Tk

Updated 2001-10-05 13:25:14

Building User Interfaces With Tcl And Tk

                                        [John Ousterhout]

Tcl/Tk Tutorial, Part III Outline

  • Basic structures: windows, widgets, processes.
  • Creating widgets: class commands.
  • Widget commands.
  • Geometry management: the placer and the packer.
  • Bindings.
  • Other commands: send, focus, selection, window manager, grabs.
  • Two examples: showVars, mkDialog.

Structure Of A Tk Application

  • Widget hierarchy.
  • One Tcl interpreter.
  • One process (can have > 1 application in a process).
  • Widget: a window with a particular look and feel.
  • Widget classes implemented by Tk:
 Frame  Menubutton      Canvas
 Label  Menu    Scrollbar
 Button Message Scale
 Checkbutton    Entry   Listbox
 Radiobutton    Text    Toplevel

The Widget Hierarchy Types Of Windows Creating Widgets

  • Each widget has a class: button, listbox, scrollbar, etc.
  • One class command for each class, used to create instances:
 button .a.b -text Quit -command exit
 scrollbar .x -orient horizontal

Configuration Options

  • Defined by class. For buttons:
        -activebackground       -disabledforeground     -justify        -underline 
        -activeforeground       -font   -padx   -width 
        -anchor -foreground     -pady   -wraplength 
        -background     -height -relief
        -bitmap -highlightbackground    -state
        -borderwidth    -highlightcolor -takefocus
        -command        -highlightthickness     -text
        -cursor -image  -textvariable
  • If not specified in command, taken from option database:
      -  Loaded from RESOURCE_MANAGER property or .Xdefaults file.
      -  May be set, queried with option command.
  • If not in option database, default provided by class.

Widget Commands

  • Tcl command for each widget, named after widget.
  • Used to reconfigure, manipulate widget:
 button .a.b
 .a.b configure -relief sunken
 .a.b flash
 scrollbar .x
 .x set 0.2 0.7
 .x get
  • Widget command is deleted when widget is destroyed.
  • Principle: all state should be readable, modifiable, anytime.

Geometry Management

  • Widgets don't control their own positions and sizes: geometry managers do.
  • Widgets don't even appear on the screen until managed by a geometry manager.
  • Geometry manager = algorithm for arranging slave windows relative to a master window.

The Placer

  • Simple but not very powerful.
  • Each slave placed individually relative to its master.

The Placer, cont'd The Packer

  • More powerful than the placer.
  • Arranges groups of slaves together (packing list).
  • Packs slaves around edges of master's cavity.
  • For each slave, in order:

The Packer: Choosing Sides The Packer: Padding The Packer: Filling Stretch widgets to fill parcels: The Packer: Filling, cont'd The Packer: Expansion Increase parcel size to absorb extra space in master:


The Packer: Expansion, cont'd Hierarchical Packing Use additional frames to create more complex arrangements: Connections

  • How to make widgets work together with application, other widgets? Tcl scripts.
  • Widget actions are Tcl commands:
 button .a.b -command exit
  • Widgets use Tcl commands to communicate with each other:
 scrollbar .s -command ".text yview"
  • Application uses widget commands to communicate with widgets.

Bindings

  • Associate Tcl scripts with X events:
 bind .b <Control-h> {backspace .t}
  • Use tags to select one or more windows:
      -  Name of window: .b
      -  Widget class: Text
      -  All windows: all
      -  Arbitrary string: foo, bar, ...

Bindings: Specifying Events

  • Specifying events:
 <Double-Control-ButtonPress-1>
 <3>
 <KeyPress>
 a

Bindings: Substitutions

  • % substitutions in binding scripts:
      -  Coordinates from event: %x and %y.
      -  Window: %W.
      -  Character from event: %A.
      -  Many more...
  • Examples:
 bind .c <B1-Motion> {move %x %y}
 bind .t <KeyPress> {insert %A}
 bind all <Help> {help %W}

Binding Order

  • What if multiple bindings match an event?
 bind .t a ...
 bind all <KeyPress> ...
  • One binding triggers per tag: most specific.
  • Default order of tags: widget, class, toplevel, all.
  • Can change tags with bindtags command:
 bindtags .b {MyButton .b foo all}
  • Can use break to skip later tags.
  • Note: these rules apply only to Tk 4.0.

More On Bindings

  • Text and canvas widgets support bindings internally:
      -  Associate tags with text or graphics:
 .t tag add foo 1.0 2.0
 .c create rect 1c 1c 2c 2c -tags foo
      -  Associate bindings with tags:
 .t bind foo <1> {...}
 .c bind foo <Enter> {...}
  • Bindings always execute at global level:
      -  If binding created in procedure, procedure's local variables aren't available at event- time.

Quoting Hell

  • Often want binding script to use some information from binding-time, some from event-time.
  • Use list commands to generate scripts.
  • Use procedures to separate event-time information from bind-time information.
 bind .x <1> {set y [expr $a + $b]}
 bind .x <1> "set y [expr $a + $b]"
 proc sety a {
    global b y
    set y [expr $a + $b]
 }
 bind .x <1> [list sety $a]

Other Tk Commands

  • The selection:
 selection get
 selection get FILE_NAME
  • Issuing commands to other Tk applications:
 send tgdb "break tkEval.c:200"
 winfo interps
  • wish tgdb ppres
  • Window information:
 winfo width .x
 winfo children .
 winfo containing $x $y

Access To Other X Facilities

  • Keyboard focus:
 focus .x.y
  • Communication with window manager:
 wm title . "Editing main.c"
 wm geometry . 300x200
 wm iconify .
  • Deleting windows:
 destroy .x
  • Grabs:
 grab .x
 grab release .x

Example #1: showVars

  • Displays values of one or more values, updates automatically:
 showVars .vars name age ssn phone
 showVars, cont'd
 proc showVars {w args} {
    toplevel $w
    wm title $w "Variable values"
    frame $w.menu -relief raised -bd 2
    pack $w.menu -side top -fill x
    menubutton $w.menu.file -text File \
        -menu $w.menu.file.m -underline 0
    pack $w.menu.file -side left
    menu $w.menu.file.m
    $w.menu.file.m add command -label Quit \
        -command "destroy $w" -underline 0
    ...
 }
 showVars, cont'd
 proc showVars {w args} {
    ...
    frame $w.bot -relief raised -bd 2
    pack $w.bot -side bottom -fill both
    label $w.bot.title -width 20 -anchor center \
        -text "Variable values:" -font \
        -Adobe-Helvetica-Medium-r-normal--*-180-*-*-*-*-*-*- 
    pack $w.bot.title -side top -fill x
    ...
 }
 showVars, cont'd
 proc showVars {w args} {
    ...
    foreach i $args {
        frame $w.bot.$i
        pack $w.bot.$i -side top -anchor w
        label $w.bot.$i.name -text "$i: "
        label $w.bot.$i.value -textvariable $i
        pack $w.bot.$i.name -side left
        pack $w.bot.$i.value -side left
    }
 }
 showVars .vars name age ssn phone

Example #2: mkDialog Creates dialog box, waits until button pressed, returns index.

 mkdialog .d "File Modified" $msg warning \
 "Save File" "Discard Changes" "Return To Editor"
 mkDialog, cont'd
 proc mkDialog {w title text bitmap args} {
    toplevel $w
    wm title $w $title
    wm protocol $w WM_DELETE_WINDOW { }
    frame $w.top -relief raised -bd 1
    pack $w.top -side top -fill both
    frame $w.bot -relief raised -bd 1
    pack $w.bot -side bottom -fill both
    label $w.msg -wraplength 3i -text $text \
        -justify left -font \
        -Adobe-Times-Medium-R-Normal--*-180-*-*-*-*-*-*
    pack $w.msg -in $w.top -side right \
        -expand 1 -fill both -padx 3m -pady 3m
    ...
 }

 mkDialog, cont'd
 proc mkdialog {w title text bitmap args} {
    ...
    if {$bitmap != ""} {
        label $w.bitmap -bitmap $bitmap
        pack $w.bitmap -in $w.top -side left \
            -padx 3m -pady 3m
    }
    ...
 }

mkDialog, cont'd

 proc mkDialog {w title text bitmap args} {
    ...
    set i 0
    foreach but $args {
        button $w.button$i -text $but \
            -command "set button $i"
        pack $w.button$i -in $w.bot -side left \
            -expand 1 -padx 3m -pady 2m
        incr i
    }
    ...
 }

mkDialog, cont'd

 proc mkDialog {w title text bitmap args} {
    global button
    ...
    grab $w
    set oldFocus [focus]
    focus $w
    tkwait variable button
    destroy $w
    focus $oldFocus
    return $button
 }

Summary

  • Creating interfaces with Tk is easy:
      -  Create widgets.
      -  Arrange with geometry managers.
      -  Connect to application, each other.
  • Power from single scripting language:
      -  For specifying user interface.
      -  For widgets to invoke application.
      -  For widgets to communicate with each other.
      -  For communicating with outside world.
      -  For changing anything dynamically.

An Overview of Tcl and Tk - An Introduction To Tcl Scripting - Writing Tcl-Based Applications in C