I have a Tcl script controlling an automated tester. So far it was a console program that took user input at the command prompt. A colleague wrote a Tk GUI that can be launched by the script. I have never used Tk myself, so I don't understand a lot of the syntax.
开发者_运维问答At the beginning of the test the script must get a unit serial number from the operator. This is the function that my colleague wrote to do that:
proc GetSerialNumber {} {
global gUserInterfaceBarCode
DisplayMessage "Enter serial number:"
.c.serialnumberbox configure -state normal
focus .c.serialnumberbox
bind .c.serialnumberbox <Return> { set gUserInterfaceBarCode [.c.serialnumberbox get] }
tkwait variable gUserInterfaceBarCode
#grid forget .c.serialnumberbox
.c.serialnumberbox configure -state disabled
}
DisplayMessage
is a procedure that simply updates a text label on the GUI.
I don't like the fact that there is a global variable gUserInterfaceBarCode
that is used to hold the serial number. Is there any way to use a local variable instead and have the procedure return that value?
If I understand correctly, if the line tkwait variable gUserInterfaceBarCode
is taken out this function will not block until that variable changes. Is this the best way to capture user input from a GUI element?
Fundamentally you need to have a variable to wait on. Unfortunately, the code for the <Return>
is executed in a different context (the global context) than the code inside your proc, and there's no way for that code to address the local variables in your proc.
However, it doesn't have to a global variable, per se -- it just needs to be globally addressable, by which I mean you could use a namespace variable instead, if that makes you feel better about it:
namespace eval GetSerialNumber {
proc GetSerialNumber {} {
DisplayMessage "Enter serial number:"
.c.serialnumberbox configure -state normal
focus .c.serialnumberbox
bind .c.serialnumberbox <Return> { set ::GetSerialNumber::result [.c.serialnumberbox get] }
tkwait variable ::GetSerialNumber::result
.c.serialnumberbox configure -state disabled
return $::GetSerialNumber::result
}
}
set serialNum [GetSerialNumber::GetSerialNumber]
Another alternative would be to explicitly delete gUserInterfaceBarCode
before returning:
tkwait variable ::gUserInterfaceBarCode
set result $::gUserInterfaceBarCode
unset ::gUserInterfaceBarCode
return $result
For what it's worth, the Tk core implementation uses the namespace approach for its own built-in dialog implementations, like the "Open File" dialog box.
精彩评论