View
228
Download
1
Embed Size (px)
Citation preview
Building User Interfaces with Tk/Tcl
Outline– Basic Structures
– Widget Creation
– Geometry Management
– Widget Commands
– Event Bindings
– Interprocess Communication
– Misc. Commands
– Examples
Goal– Understand Tk syntax
– Understand Tk built-in commands
Reading– Ch. 19-31, Practical Programming in Tcl and Tk
Structure of a Tk Application
1. Widget hierarchy
2. One Tcl interpreter
3. One process– can have > 1 application in a process
• Widget = window with particular look and feel
• Widget classes implemented by Tk– frame, toplevel
– label, button, checkbutton, radiobutton
– menu, menubutton
– message, dialog
– entry, text, listbox
– canvas
– scrollbar, scale
Types of Windows
Main window Top-level window
Internal windows
.listbox
.
.menu .scroll
.menu.file .menu.help
.dlg
.dlg.msg
.dlg.yes
.dlg.no
Creating Widgets
• Each widget has a class: button, listbox, etc.
• Tcl command named after each class, used to create instances
button .a.b -text Quit -command exit
scrollbar .x -orient horizontal
class name
window name
configurationoptions
Configuration Options
• Defined by class– for buttons: activeBackground, activeForeground,
anchor, background, bitmap, borderWidth, command, cursor, disableForeground, font, foreground, height, padx, pady, relief, state, text, textVariable, width
• If not specified on command line, taken from option database– loaded from RESOURCE_MANAGER property or .Xdefaults
file
– may be set, queried with Tcl commands
option add *Button.relief sunken
• If not in option database, use default provided by class implementation
Geometry Management
• Widgets do not control their own positions and sizes, geometry managers do
• Widgets do not appear on screen until managed by geometry manager
• Geometry manager = algorithm for arranging slave windows relative to master window
GeometryManager
Geometry ofmaster
Requested sizefrom slave
Parameters fromapplication designer
Size and locationof slave
Requested sizefor master
The Placer
• Simple, but not very powerful
• Each slave placed individually relative to its master
place .x -x 0 -y 0
place .x -relx 0.5 -rely 0.5 \-height 3c -anchor center
place .x -relx 0.5 \-y 1.0c -anchor n
place .x -relheight 0.5 \-relwidth 0.5 -relx 0 -rely 0.5
The Packer
• Much more powerful than placer
• Arranges groups of slaves together
• Packs slaves around edges of master’s cavity
• For each slave in order:1. Pick a side of the master
2. Slice off a frame for slave
3. Possibly grow slave to fill frame
4. Position slave in frame
Packer Examples
pack .a -side leftpack .b -side leftpack .c -side left
pack .a -side top -anchor wpack .b -side top -anchor w \
-pady .5cpack .c -side top -anchor w
pack .a -side top -fill xpack .b -side right -fill ypack .c -padx 0.5c -pady 1c \
-fill both
.a .b .c
.a .b .c
.a .b .c
.a .b .c
.b
.c
.a
.a
.b.c
Packer Advantages
• Considers relationships between slaves– constraint-like placement
– row and column arrangements easy to achieve
– adjusts arrangement if slave requests a different size
• Requests size on behalf of master– just large enough for all slaves
– adjusts if slaves request different sizes
– permits hierarchical geometry management
» constrains propagate in hierarchy
Widget Commands
• Tcl command for each widget, named after widget’s path name– created with widget
• Used to reconfigure, manipulate widgetbutton .a.b
.a.b configure -relief sunken
.a.b flash
scrollbar .x
.x set 0.2 0.4
.x get
• Widget command deleted automatically when widget is destroyed
• Principle: all state should be readable, modifiable, anytime
Connections
buttonrelease
click onarrow
• Question: How to make widgets work together with application, other widgets?
• Answer: Tcl commands
• Widget actions are Tcl commandsbutton .a.b -command exit
• Widgets use Tcl commands to communicate with each otherscrollbar .x -command “.y yview”
• Application uses widget commands to communicate with widgets
exit
.y yview 9
Bindings
• Associate Tcl with mouse/keyboard events
bind .t <Control-h> {backspace .t}
• Can select one or more windows– single window: .t
– all windows in a class: Text
– all windows: all
• Specifying events
<Double-Control-ButtonPress-1>
<3>
<Any-KeyPress>
Window/Tag Event Sequence Script
ModifiersEventType
Button orKeysym
Bindings (cont.)
• % substitutions in binding scripts– coordinates from event: %x and %y
– window: %W
– character from event: %A
– etc.
• Examplesbind .c <B1-Motion> {move %x %y}
bind .t <Any-KeyPress> {insert %A}
bind all <Help> {help %W}
• Only one binding triggers from each event for each tag/window in order– window before class before toplevel before all
– if >1 binding with same tag match, most specific executes
Bindings (cont.)
• Binding tags– event not bound to window, class, or all is bound to a tag
» any user-defined string
– every window has list of binding tags
– apply event to each tag in order
– most specific binding that matches tag/event is executed
• Default– window name, class name, nearest toplevel ancestor name, all
• bindtags window ?tagList?– can read/modify tag list for window
– add new bindings, modify order– bindtags .b {all . Button .b} - reverse default order
• Use to manage complex binding sets
Other Tk Commands
• The selectionselection get
selection get FILE_NAME
• Issuing commands to other Tk applicationssend tgdb “break tkEval.c:200”
winfo interps
returns: wish tgdb ppres
• Window informationwinfo width .x
winfo children .x
winfo containing $x $y
Access to Other Window Facilities
• Keyboard focusfocus .x.y
• Communication with window managerwm title . “Editing main.c”
wm geometry . 300x300
wm iconify .
• Deleting windowsdestroy .x
• Grabsgrab .x
grab release .x
Example 1: Dialog Box
toplevel .dmessage .d.top -width 3i -bd 2 \
-relief raised -justify center -font \*-helvetica-medium-r-normal--*-240-* \-text “File main.c hasn’t been \saved to disk since it was last \modified. What should I do?”
pack .d.top -side top -fill both
Dialog Box Cont.
frame .d.botpack .d.bot -side bottom -fill bothbutton .d.bot.left -text “Save File” \
-command “quit save”pack .d.bot.left -side left \
-expand yes -padx 20 -pady 20button .d.bot.mid -text “Quit Anyway” \
-command “quit quit”pack .d.bot.mid -side left \
-expand yes -padx 20 -pady 20
Dialog Box Cont.
button .d.bot.right -text “Return to Editor” \-command “quit return”
pack .d.bot.right -side left \-expand yes -padx 20 -pady 20
proc quit button {puts stdout “You pressed the \
$button button; bye-bye”destroy .d
}
Example 2: Browser
listbox .list -yscroll “.scroll set” \-relief raised -width 20 -height 15
pack .list -side leftscrollbar .scroll -command “.list yview”pack .scroll -side right -fill y
Browser Cont.
if {$argc > 0} {set dir [lindex $argv 0]
} else {set dir .}foreach i [exec ls -a $dir] {
.list insert end $i}
Browser Cont.
bind .list <Double-Button-1> {browse $dir [selection get]
bind .list <Control-c> {destroy .}focus .list
proc browse {dir file} {if {$dir != “.”} {
set file $dir/$file}if [file isdirectory $file] {
exec browse $file &} else {
if [file isfile $file] {exec $env(EDITOR) $file &
} else {puts stdout “\”$file\” isn’t \
a regular file or directory”}
}
}
Example 3: Scrolling Canvas
• Top-level canvas with x and y scrollbars– 20x10 array of rectangles
with (i,j) index label
– select and print rectangle labels
– pan canvas
Example 3: Scrolling Canvas
• Create top level widget• Inform window manager of size, title, etc.
proc mkScroll {{w .cscroll}} { catch {destroy $w} toplevel $w wm geometry $w +300+300 wm title $w "Scrollable Canvas Demonstration" wm iconname $w "Canvas" wm minsize $w 100 100
Scrolling Canvas Cont.
• Create header message and quit button
message $w.msg \-font -Adobe-Times-Medium-R-Normal-*-180-* \-aspect 300 -relief raised -bd 2 -text {This window displays a canvas widget that can be scrolled either using the scrollbars or by dragging with button 2 in the canvas. If you click button 1 on one of the rectangles, its indices will be printed on stdout.}
frame $w.frame -relief raised -bd 2
button $w.ok -text "OK" -command "destroy $w" pack $w.msg -side top -fill x pack $w.ok -side bottom -pady 5 pack $w.frame -side top -expand yes -fill both
Scrolling Canvas Cont.
• Create canvas and scrollbars• fix maximum scrolling/drawing region• set up link between scroll bars and canvas
set c $w.frame.ccanvas $c -scrollregion {-10c -10c 50c 20c} \
-xscroll "$w.frame.hscroll set" \-yscroll "$w.frame.vscroll set"
scrollbar $w.frame.vscroll -relief sunken \-command "$c yview"
scrollbar $w.frame.hscroll -orient horiz \-relief sunken -command "$c xview"
pack $w.frame.vscroll -side right -fill y pack $w.frame.hscroll -side bottom -fill x pack $c -expand yes -fill both
Scrolling Canvas Cont.
• Draw 20x10 array of rectangles and labels• rectangles of background color outlined in black• black text “i, j” centered in rectangle
set bg [$c cget -bg] for {set i 0} {$i < 20} {incr i} {
set x [expr {-10 + 3*$i}]for {set j 0; set y -10} {$j < 10} {incr j; incr y 3} { $c create rect ${x}c ${y}c [expr $x+2]c \
[expr $y+2]c -outline black -fill $bg -tags rect $c create text [expr $x+1]c [expr $y+1]c \
-text "$i,$j" -anchor center -tags text}
}
Scrolling Canvas Cont.
• Bind canvas item events to mouse callback procedures
• highlight rectangle when mouse enters it• unhighlight rectangle when mouse leaves• print text label when button 1 clicked over rectangle
• Pan canvas when dragging with button 2 down
$c bind all <Any-Enter> "scrollEnter $c" $c bind all <Any-Leave> "scrollLeave $c" $c bind all <1> "scrollButton $c" bind $c <2> "$c scan mark %x %y" bind $c <B2-Motion> "$c scan dragto %x %y"}# end of mkScroll
Scrolling Canvas Cont.
• Mouse event callback procedures• scrollEnter - called when entering rectangle• scrollLeave - called when leaving rectangle• scrollButton - called when button click in rectangle
proc scrollEnter canvas { global oldFill set id [$canvas find withtag current] if {[lsearch [$canvas gettags current] text] >= 0} {
set id [expr $id-1] } set oldFill [$canvas itemcget $id -fill] if {[tk colormodel $canvas] == "color"} {
$canvas itemconfigure $id -fill SeaGreen1 } else {
$canvas itemconfigure $id -fill black$canvas itemconfigure [expr $id+1] -fill white
}}
Scrolling Canvas Cont.
proc scrollLeave canvas { global oldFill set id [$canvas find withtag current] if {[lsearch [$canvas gettags current] text] >= 0} {
set id [expr $id-1] } $canvas itemconfigure $id -fill $oldFill $canvas itemconfigure [expr $id+1] -fill black}
proc scrollButton canvas { global oldFill set id [$canvas find withtag current] if {[lsearch [$canvas gettags current] text] < 0} {
set id [expr $id+1] } puts stdout "You buttoned at \
[lindex [$canvas itemconf $id -text] 4]"}mkScroll
Summary
• Creating interfaces with Tcl scripts 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