Googie (21.05.2005) - I've just created some Itcl-based modal widgets and I'd like to share them with others :) There are 2 widgets so far, meaby there'll be more... meaby someone else could add ones.
I know that there is tk_messageBox, but MsgBox looks better (I think so) under X11 and it's Tile-ready.
Modal window (it could be not-modal but callback-mode, optionally) grabs application input (with grab) and halts code execution at exec method call until user response in that window.
Here's example, what you can do with that widgets:
package require Tk package require Itcl namespace import itcl::* source modal.tcl ;# this is base class for all modal widgets source msgbox.tcl source inputdialog.tcl MsgBox msg .question -message "Are you sure about that?" -title "Question" -buttons [list "Yes" "Not sure" "No" "I don't understeand"] -default 0 # here some code, if you want switch -- [msg exec] { 0 { puts "He/She wants!" } 1 { puts "He/She isn't sure!" } 2 { puts "He/She doesn't want!" } 3 { puts "He/She doesn't understeand!" } } InputDialog dialog .input -message "Type some value" -title "Input dialog" -default "Some initial string" # here's some your custom code set ret [dialog exec] if {$ret != ""} { puts "Entered: $ret" } else { puts "Entered empty string or clicked cancel/close button" } proc test {button} { puts "Clicked button $button" } MsgBox msg .msg -modal 0 -command test -message "Just test" msg exec puts "This command is executed immediately, instead waiting for user respond in above MsgBox."
And here's code of 2 classes used above and the 3rd class needed by these 2:
class Modal { constructor {Path Args} {} destructor {} protected { variable modal 1 variable command "" variable path variable parent "" variable default 0 variable title "Modal" method center {path {parent {}}} } public { variable sleep method exec {} method clicked {btn} } } body Modal::constructor {Path Args} { set path $Path foreach {opt val} $Args { switch -- $opt { "-modal" { set modal $val } "-command" { set command $val } "-title" { set title $val } "-parent" { set parent "" } "-default" { set default $val } } } } body Modal::destructor {} { destroy $path } body Modal::center {path {parent {}}} { update if {$parent == ""} { set sp [split $path .] if {[llength $sp] > 2} { set parent [join [lrange $sp 0 end-1] .] } else { set parent . } } set sp [split [wm geometry $parent] +] set px [lindex $sp 1] set py [lindex $sp 2] set wd [winfo reqwidth $path] set ht [winfo reqheight $path] set x [expr {$px+([winfo reqwidth $parent]-$wd)/2}] set y [expr {$py+([winfo reqheight $parent]-$ht)/2}] wm geometry $path +$x+$y } body Modal::clicked {btn} { } body Modal::exec {} { } class MsgBox { inherit Modal constructor {Path args} { Modal::constructor $Path $args } {} private { variable buttons "ok" variable msg "" } public { method exec {} method clicked {btn} } } body MsgBox::constructor {Path args} { set title "MsgBox" foreach {opt val} $args { switch -- $opt { "-message" { set msg $val } "-buttons" { set buttons $val } } } } body MsgBox::exec {} { toplevel $path frame $path.u pack $path.u -side top -fill both label $path.u.l -text "" -font "helvetica 12 bold" -relief groove -bd 2 pack $path.u.l -side top -fill x -pady 0.1c -padx 0.2c frame $path.d pack $path.d -side bottom -fill x frame $path.d.f pack $path.d.f -side bottom set i 0 foreach txt $buttons { button $path.d.f.$i -text $txt -command "$this clicked $i" pack $path.d.f.$i -side left -pady 3 incr i } bind $path <Destroy> "catch {$this configure -sleep $default}" wm title $path $title $path.u.l configure -text $msg center $path $parent update wm resizable $path 0 0 if {$modal} { if {$parent == ""} { set sp [split $path .] if {[llength $sp] > 2} { set parent [join [lrange $sp 0 end-1] .] } else { set parent . } } grab $path vwait [scope sleep] set retval $sleep delete object $this return $retval } } body MsgBox::clicked {btn} { if {$command != ""} { eval $command $btn } else { set sleep $btn } } class InputDialog { inherit Modal constructor {Path args} { Modal::constructor $Path $args } {} destructor {} private { variable msg "" } public { method exec {} method clicked {btn} } } body InputDialog::constructor {Path args} { set path $Path foreach {opt val} $args { switch -- $opt { "-message" { set msg $val } } } } body InputDialog::destructor {} { destroy $path } body InputDialog::exec {} { toplevel $path frame $path.u pack $path.u -side top -fill both label $path.u.l -text "" -font "helvetica 12 bold" -justify left pack $path.u.l -side top -fill x -pady 2 -padx 0.2c entry $path.u.e pack $path.u.e -side top -fill x -pady 0.1c -padx 0.2c frame $path.d pack $path.d -side bottom -fill x frame $path.d.f pack $path.d.f -side bottom button $path.d.f.ok -text "Ok" -command "$this clicked ok" pack $path.d.f.ok -side left -pady 3 button $path.d.f.cancel -text "Cancel" -command "$this clicked cancel" pack $path.d.f.cancel -side left -pady 3 bind $path <Destroy> "catch {$this configure -sleep {}}" wm title $path $title $path.u.l configure -text $msg center $path $parent update wm resizable $path 0 0 focus -force $path.u.e $path.u.e insert end $default $path.u.e selection range 0 end if {$modal} { if {$parent == ""} { set sp [split $path .] if {[llength $sp] > 2} { set parent [join [lrange $sp 0 end-1] .] } else { set parent . } } grab $path vwait [scope sleep] set retval $sleep delete object $this return $retval } } body InputDialog::clicked {btn} { if {$btn == "cancel"} { set sleep "" return } if {$command != ""} { eval $command [$path.u.e get] } else { set sleep [$path.u.e get] } }
[ Category Widget ]