countdownMsgBox

The TWAPI based countdownMsgBox is made to use the normal Windows message box (tcl_messageBox) with a countdown allowing an automated closing of this message box with the return of a default button.

The syntax is basically taken from tcl_messageBox, but slightly extended by ...

-message (string | formatString)
the message string, probably used with format to include the current countdown number into the message
-title (string | formatString)
the title string, probably used with format to include the current countdown number into the title
-format (message | title)
specifies, if to use the message or title string to format it using the current countdown number (default: message)
-countdown integer
specifies the seconds to count down (default: 30)
-step integer
specifies the step in seconds to decrement the current count down (default: 1)
-closeonend ?boolean?
tells, if to close automatically the message box on the end of the count down
-closeonend (abort | cancel | ignore | no | ok | retry | yes)
specifies the default button to be returned on an automated closing of the message box (default: ok)

This countdownMsgBox relies on the structure of the default Windows message box, which has a certain window class and only two so called STATIC elements (the icon and the message text). This means, that the message text is modified on each count down decrementation using TWAPI and that the message box is, if wanted, closed using TWAPI.

Now the tcl 8.5+ related source ...


 package provide countdownMsgBox 2.0;

 package require twapi 2;

 uplevel #0 {
     namespace eval ::countdownMsgBox {
         proc updateMsgBox {closedOnEndVar existingHwnds format title message countdown step closeOnEnd} {
             set hwnds [twapi::find_windows -pids [pid] -toplevel 1 -class #32770];

             if {![llength $hwnds]} {
                 return;
             }

             foreach hwnd [lreverse $hwnds] {
                 if {$hwnd ni $existingHwnds} {
                     if {$format eq "title"} {
                         twapi::set_window_text $hwnd [format $title $countdown];
                     } else {
                         set msgHwnd [lindex [twapi::get_child_windows $hwnd] end];
                         twapi::set_window_text $msgHwnd [format $message $countdown];
                     }

                     break;
                 }
             }

             if {$countdown > 0} {
                 after \
                     $step \
                     [list \
                         namespace inscope [namespace current] updateMsgBox \
                             $closedOnEndVar \
                             $existingHwnds \
                             $format $title $message \
                             [incr countdown -1] $step \
                             $closeOnEnd \
                     ];
             } elseif {$closeOnEnd} {
                 variable $closedOnEndVar;

                 twapi::close_window $hwnd;

                 set $closedOnEndVar 1;
             }

             return;
         }

         proc countdownMsgBox {args} {
             array set options [twapi::parseargs args {
                 {parent.arg ""}
                 {icon.arg info {error info question warning}}
                 {type.arg okcancel {abortretryignore ok okcancel retrycancel yesno yesnocancel}}
                 {title.arg ""}
                 {message.arg ""}
                 {format.arg message {title message}}
                 {countdown.int 30}
                 {step.int 1}
                 {closeonend.switch}
                 {closeonendbutton.arg ok {abort cancel ignore no ok retry yes}}
             }];

             set closedOnEndVar  [expr {srand(round(rand()*1000000))}];

             variable $closedOnEndVar;

             set $closedOnEndVar 0;

             set step [expr {round($options(step) * 1000)}];
             set parent [list];

             if {$options(parent) ne ""} {
                 set parent  [list -parent $options(parent)];
             }

             set existingHwnds [twapi::find_windows -pids [pid] -toplevel 1 -class #32770];

             after \
                 $step \
                 [list \
                     namespace inscope [namespace current] updateMsgBox \
                         $closedOnEndVar \
                         $existingHwnds \
                         $options(format) $options(title) $options(message) \
                         [expr {$options(countdown) - 1}] $step \
                         $options(closeonend) \
                 ];

             set rc [tk_messageBox \
                 {*}$parent \
                 -icon $options(icon) \
                 -type $options(type) \
                 -title [expr {$options(format) eq "title" ? [format $options(title) $options(countdown)] : $options(title)}] \
                 -message [expr {$options(format) eq "message" ? [format $options(message) $options(countdown)] : $options(message)}] \
             ];

             if {[set $closedOnEndVar] && ($options(closeonendbutton) ne "")} {
                 return $options(closeonendbutton);
             }

             return $rc;
         }

         namespace export -clear countdownMsgBox;
     }

     namespace import -force countdownMsgBox::*;
 }

Example usages:

 countdownMsgBox -parent . -icon question -title "countdown" -message {Countdown at %ld seconds} -format message -countdown 10;
 countdownMsgBox -parent . -icon question -title "countdown" -message {Countdown at %ld seconds} -format message -countdown 10 -closeonend -closeonendbutton cancel;