TCL:Variable value is not updated after clicking checkbutton - tcl

I am trying to set up a sequence of checkbuttons, when clicked these will set the variable value linked to these buttons as 1.
Run button will only run the checks for which checkbutton is selected.
The global variable value eg: check_H1 is not updated when button is clicked.
#!/usr/local/bin/wish
package require Tk
frame .top -width 50 -height 30 -borderwidth 5 -padx 5 -pady 5 -relief raised
checkbutton .top.c1 -text H1 -variable "check_H1" -command {set_h1}
checkbutton .top.c2 -text H2 -variable "check_H2" -command {set_h2}
checkbutton .top.c3 -text H3 -variable "check_H3" -command {set_h3}
checkbutton .top.c4 -text H4 -variable "check_H4" -command {set_h4}
checkbutton .top.c5 -text H5 -variable "check_H5" -command {set_h5}
checkbutton .top.c6 -text H6 -variable "check_H6" -command {set_h6}
button .top.b1 -text "RUN" -command [list select $check_H1 $check_H2 $check_H3 $check_H4 $check_H5 $check_H6]
grid .top
grid .top.c1 -row 2 -column 2
grid .top.c2 -row 2 -column 3
grid .top.c3 -row 3 -column 2
grid .top.c4 -row 3 -column 3
grid .top.c5 -row 4 -column 2
grid .top.c6 -row 4 -column 3
grid .top.b1 -row 5 -column 5
proc select {check_H1 check_H2 check_H3 check_H4 check_H5 check_H6} {
#upvar check_H1 check_H2 check_H3 sa3 check_H4 sa4 check_H5 sa5 check_H6 sa6
puts "Value of H1 is $check_H1\n"
puts $check_H2
puts $check_H3
puts $check_H4
puts $check_H5
puts $check_H6
if {$check_H1 == 1} {
run_h1
}
if {$check_H2 ==1} {
run_h2
}
if {$check_H3 ==1} {
run_h3
}
if {$check_H4 ==1} {
run_h4
}
if {$check_H5 ==1} {
run_h5
}
if {$check_H6 ==1} {
run_h6
}
}
proc set_h1 {} {
global check_H1
set check_H1 1
puts $check_H1
puts "H1 is set\n"
}
proc set_h2 {} {
global check_H2
set check_H2 1
puts "H2 is set\n"
}
proc set_h3 {} {
global check_H3
set check_H3 1
puts "H3 is set\n"
}
proc set_h4 {} {
set check_H4 1
puts "H4 is set\n"
}
proc set_h5 {} {
set check_H5 1
puts "H5 is set\n"
}
proc set_h6 {} {
set check_H6 1
puts "H6 is set\n"
}
proc run_h1 {} {
global check_H1
puts "this loop is for H1\n"
}
proc run_h2 {} {
global check_H2
puts "this loop is for H2\n"
}

When running the script, it feels a lot of things don't work as I think it was intended to. I changed a few things, and removed the variables from the button command since the variables are passed to the command to be run at the start rather than at the point the button is pressed.
I have also removed all the set check_HX 1 because they force the checkbutton to a single state. That said, I didn't touch any other functionality.
package require Tk
frame .top -width 50 -height 30 -borderwidth 5 -padx 5 -pady 5 -relief raised
checkbutton .top.c1 -text H1 -variable "check_H1" -command {set_h1}
checkbutton .top.c2 -text H2 -variable "check_H2" -command {set_h2}
checkbutton .top.c3 -text H3 -variable "check_H3" -command {set_h3}
checkbutton .top.c4 -text H4 -variable "check_H4" -command {set_h4}
checkbutton .top.c5 -text H5 -variable "check_H5" -command {set_h5}
checkbutton .top.c6 -text H6 -variable "check_H6" -command {set_h6}
button .top.b1 -text "RUN" -command select
grid .top
grid .top.c1 -row 2 -column 2
grid .top.c2 -row 2 -column 3
grid .top.c3 -row 3 -column 2
grid .top.c4 -row 3 -column 3
grid .top.c5 -row 4 -column 2
grid .top.c6 -row 4 -column 3
grid .top.b1 -row 5 -column 5
proc select {} {
global check_H1 check_H2 check_H3 check_H4 check_H5 check_H6
puts "Value of H1 is $check_H1"
puts "Value of H2 is $check_H2"
puts "Value of H3 is $check_H3"
puts "Value of H4 is $check_H4"
puts "Value of H5 is $check_H5"
puts "Value of H6 is $check_H6"
if {$check_H1 == 1} {run_h1}
if {$check_H2 == 1} {run_h2}
if {$check_H3 == 1} {run_h3}
if {$check_H4 == 1} {run_h4}
if {$check_H5 == 1} {run_h5}
if {$check_H6 == 1} {run_h6}
}
proc set_h1 {} {
global check_H1
puts "H1 is set to $check_H1"
}
proc set_h2 {} {
global check_H2
puts "H2 is set to $check_H2"
}
proc set_h3 {} {
global check_H3
puts "H3 is set to $check_H3"
}
proc set_h4 {} {
global check_H4
puts "H4 is set to $check_H4"
}
proc set_h5 {} {
global check_H5
puts "H5 is set to $check_H5"
}
proc set_h6 {} {
global check_H6
puts "H6 is set to $check_H6"
}
proc run_h1 {} {
global check_H1
puts "This loop is for H1 $check_H1"
}
proc run_h2 {} {
global check_H2
puts "this loop is for H2 $check_H2"
}
proc run_h3 {} {
global check_H3
puts "this loop is for H3 $check_H3"
}
proc run_h4 {} {
global check_H4
puts "this loop is for H4 $check_H4"
}
proc run_h5 {} {
global check_H5
puts "this loop is for H5 $check_H5"
}
proc run_h6 {} {
global check_H6
puts "this loop is for H6 $check_H6"
}

Related

Reposition file name from button to entry and use file names as global variables

Currently:
Before execution (fig. 1)
after execution (fig. 2)
I am poor at tcl/tk. But nowadays I am studying tcl/tk for my work. I want to make GUI like figures. figure 1 is before clicking buttons. If I click right-side button and select files, the file names appear in the button text. I want to position these names in the middle-side entry region and want to use these file names as global variables. Here is my code. Could anyone help me?
#-------------------------------------------------------------------------
namespace eval ::dyna::partupdate {
variable p_mainWin ".partupdate";
variable str_curDir [file dirname [info script]];
variable str_basefile "";
variable str_appendfile "";
variable str_spotweldfile "";
variable str_outputfile "";
}
set types {
{"LS-DYNA Files" {.key .k .dyn .d } }
{"IGES Files" {.iges .igs } }
{"MCF Files" {.mcf } }
{"All files" *}
}
##############################################################################
##### Procedure Name: ::dyna::partupdate::CreateGUI
##### Functionality: creates the main window for file selection
##############################################################################
proc ::dyna::partupdate::CreateGUI {} {
variable p_mainWin;
destroy $p_mainWin;
set base [ toplevel $p_mainWin];
wm title $base {Update FE Model};
wm resizable $base 1 1;
set frm_main [frame $base.frm_main];
pack $frm_main -side top -anchor nw -padx 0 -pady 0;
set frm_fileselect [frame $frm_main.frm_fileselect -bd 0 -relief groove];
set frm_create [frame $frm_main.frm_create -bd 0 -relief groove]
# pack $frm_create -side right -anchor ne -padx 0 -pady 4;
grid $frm_fileselect -row 0 -padx 1 -pady 4 -sticky nw;
grid $frm_create -row 3 -padx 1 -pady 4 -sticky ne;
# set frm_create [frame $frm_main.frm_create -bd 0 -relief groove]
# pack $frm_create -side right -anchor ne -padx 0 -pady 4;
# UI for base file
set lbl_basefile [label $frm_fileselect.lbl_basefileName -text "Base File"];
set ent_basefile [entry $frm_fileselect.ent_basefileName -width 30 \
-textvariable "::dyna::partupdate::str_basefile" -state disabled];
set btn_basefile [button $frm_fileselect.btn_basefile -text " ... " \
-command "::dyna::partupdate::onSelect $frm_fileselect.btn_basefile" ]
grid $lbl_basefile -row 0 -col 0 -padx 5 -pady 7 -sticky nw;
grid $ent_basefile -row 0 -col 1 -padx 5 -pady 7 -sticky nw;
grid $btn_basefile -row 0 -col 2 -padx 0 -pady 6 -sticky nw;
# UI for appended file
set lbl_appendfile [label $frm_fileselect.lbl_appendfileName -text "Appended File"];
set ent_appendfile [entry $frm_fileselect.ent_appendfileName -width 30 \
-textvariable "::dyna::partupdate::str_appendfile" -state disabled];
set btn_appendfile [button $frm_fileselect.btn_appendfile -text " ... " \
-command "::dyna::partupdate::onSelect $frm_fileselect.btn_appendfile" ]
grid $lbl_appendfile -row 1 -col 0 -padx 5 -pady 2 -sticky nw;
grid $ent_appendfile -row 1 -col 1 -padx 5 -pady 2 -sticky nw;
grid $btn_appendfile -row 1 -col 2 -padx 0 -pady 6 -sticky nw;
# UI for spotweld file
set lbl_spotweldfile [label $frm_fileselect.lbl_spotweldfileName -text "Spotweld File"];
set ent_spotweldfile [entry $frm_fileselect.ent_spotweldfileName -width 30 \
-textvariable "::dyna::partupdate::str_spotweldfile" -state disabled];
set btn_spotweldfile [button $frm_fileselect.btn_spotweldfile -text " ... " \
-command "::dyna::partupdate::onSelect $frm_fileselect.btn_spotweldfile" ]
grid $lbl_spotweldfile -row 2 -col 0 -padx 5 -pady 2 -sticky nw;
grid $ent_spotweldfile -row 2 -col 1 -padx 5 -pady 2 -sticky nw;
grid $btn_spotweldfile -row 2 -col 2 -padx 0 -pady 6 -sticky nw;
# UI for output file
set lbl_outputfile [label $frm_fileselect.lbl_outputfileName -text "Output File"];
set ent_outputfile [entry $frm_fileselect.ent_outputfileName -width 30 \
-textvariable "::dyna::partupdate::str_outputfile" -state disabled];
set btn_outputfile [button $frm_fileselect.btn_outputfile -text " ... " \
-command "::dyna::partupdate::saveAs $frm_fileselect.btn_outputfile" ]
grid $lbl_outputfile -row 3 -col 0 -padx 5 -pady 2 -sticky nw;
grid $ent_outputfile -row 3 -col 1 -padx 5 -pady 2 -sticky nw;
grid $btn_outputfile -row 3 -col 2 -padx 0 -pady 6 -sticky nw;
set btn_update [hwt::CanvasButton $frm_create.btn_update \
[::hwt::DluWidth 40] [::hwt::DluHeight 14] \
-command "::dyna::partupdate::uPDATE" \
-text "Update" ]
set btn_close [hwt::CanvasButton $frm_create.btn_close \
[::hwt::DluWidth 40] [::hwt::DluHeight 14] \
-command "::dyna::partupdate::CloseWindow" \
-text "Close" ]
pack $btn_update -anchor ne -padx 5 -pady 5 -side left;
pack $btn_close -anchor ne -padx 5 -pady 5 -side left;
}
proc ::dyna::partupdate::onSelect { label } {
global types
set file [tk_getOpenFile -filetypes $types -parent .]
$label configure -text $file
}
proc ::dyna::partupdate::saveAs { label } {
global types
set file [tk_getSaveFile -filetypes $types -parent . -initialdir .]
$label configure -text $file
}
proc ::dyna::partupdate::uPDATE { args } {
variable str_basefile;
variable str_appendfile;
variable str_spotweldfile;
variable str_outputfile;
set executable C:\CENSor\\CENSor.exe
# base file name should not be empty
if {$str_basefile == ""} {
tk_messageBox -message "Please select an base file." -title "aaa" \
-type ok -icon info;
return;
}
# append file name should not be empty
if {$str_appendfile == ""} {
tk_messageBox -message "Please select an appended file." -title "aaa" \
-type ok -icon info;
return;
}
# execution case
if {$str_spotweldfile == ""} {
exec $executable -e 0 $str_outputfile $str_basefile $str_appendfile
}
else {
exec $executable -e 0 $str_outputfile $str_basefile $str_appendfile $str_spotweldfile
}
}
proc ::dyna::partupdate::CloseWindow { args } {
variable p_mainWin;
set windowPath [lindex $args 0];
if {[winfo exists $p_mainWin]} {
destroy $p_mainWin
}
}
# ----- bring up the main gui --------
::dyna::partupdate::CreateGUI;
For the first one, this line:
set btn_basefile [button $frm_fileselect.btn_basefile -text " ... " \
-command "::dyna::partupdate::onSelect $frm_fileselect.btn_basefile" ]
will execute this proc:
proc ::dyna::partupdate::onSelect { label } {
global types
set file [tk_getOpenFile -filetypes $types -parent .]
$label configure -text $file
}
The first line above will update the widget $frm_fileselect.btn_basefile which is the button, when onSelect is executed. You will first need to change the first line to modify the entry box, like so:
set btn_basefile [button $frm_fileselect.btn_basefile -text " ... " \
-command "::dyna::partupdate::onSelect $frm_fileselect.ent_basefile" ]
Then change the proc so that it is able to edit the entry text (entries don't have a -text option, you have to insert. Usually it's better to delete everything just in case)
proc ::dyna::partupdate::onSelect { label } {
global types
set file [tk_getOpenFile -filetypes $types -parent .]
$label configure -state normal ;# makes the entry normal to allow editing
$label delete 0 end ;# delete everything
$label insert end $file ;# insert the text
$label configure -state disabled ;# disable the entry again
}
Then you will have to modify the remaining 3 buttons similarly:
set btn_appendfile [button $frm_fileselect.btn_appendfile -text " ... " \
-command "::dyna::partupdate::onSelect $frm_fileselect.ent_appendfile" ]
set btn_spotweldfile [button $frm_fileselect.btn_spotweldfile -text " ... " \
-command "::dyna::partupdate::onSelect $frm_fileselect.ent_spotweldfile" ]
set btn_outputfile [button $frm_fileselect.btn_outputfile -text " ... " \
-command "::dyna::partupdate::saveAs $frm_fileselect.ent_outputfile" ]
manual for entry widget
As for the last part, you don't really need them to be global. You can use widget get, for example:
set filename [.partupdate.frm_main.frm_fileselect.ent_basefile get]
Will give you the text in the Base File entry (of course, if you have the widget path in a variable, it'll be easier)
set filename [.partupdate.frm_main.frm_fileselect.ent_spotweldfile get]
Will give you the one for Spotweld File, and so on.
Sidenote: I would probably rename the variable in onSelect from label to entry.

Radio buttons behaving as one

I am building a dialog from a database and using the key as the variable for the radio buttons. Whenever I click on a radio button, all the buttons in the same column change. There are top level variables with the names in the dictionary
#!/usr/bin/tclsh
package require Tk
variable dict_config
set dict_config [dict create]
dict set dict_config config_single_step { 0 "Single step" "Single step" "Run" }
dict set dict_config config_load { 0 "Load" "No load on startup" "Load oad on startup" }
dict set dict_config config_news { 0 "News" "No news" "News Feed" }
# Callback to set the value
proc SetValue { ix val } {
puts "Setting $ix to $val"
variable dict_config
set list_item [dict get $dict_config $ix]
dict set dict_config $ix [lreplace $list_item 0 0 $val]
}
proc todo {} {
puts "Coming soon to a screen near you"
}
proc DisplayOptions { dict_config } {
set row 0
dict for { ix list_item } $dict_config {
# Extract data from the list
set lab [lindex $list_item 1]
set zero [lindex $list_item 2]
set one [lindex $list_item 3]
incr row
# set dummy variable so the radio buttons respond correctly.
set $ix [lindex $list_item 0]
upvar 0 $ix debvar
# Create widgets
label .lab_$row -text $lab
radiobutton .zero_$row -text $zero -variable debvar -value 0 -command "SetValue $ix 0"
radiobutton .one_$row -text $one -variable debvar -value 1 -command "SetValue $ix 1"
if { $debvar == 0 } {
.zero_$row select
} else {
.one_$row select
}
# Layout widgets
grid .lab_$row -sticky e -row $row -column 0
grid .zero_$row -sticky w -row $row -column 1
grid .one_$row -sticky w -row $row -column 2
}
incr row
grid [button .butSave -text "Save" -command "todo"] -row $row -column 0
}
# Let the user change them
DisplayOptions $dict_config
I have also tried $debvar - same thing happens. I can get it to work if I change the loop body to
# Extract data from the list
set lab [lindex $list_item 1]
set zero [lindex $list_item 2]
set one [lindex $list_item 3]
incr row
# set dummy variable so the radio buttons respond correctly.
set r_$row [lindex $list_item 0]
# Create widgets
label .lab_$row -text $lab
radiobutton .zero_$row -text $zero -variable r_$row -value 0 -command "SetValue $ix 0"
radiobutton .one_$row -text $one -variable r_$row -value 1 -command "SetValue $ix 1"
if { r_$row == 0 } {
.zero_$row select
} else {
.one_$row select
}
# Layout widgets
grid .lab_$row -sticky e -row $row -column 0
grid .zero_$row -sticky w -row $row -column 1
grid .one_$row -sticky w -row $row -column 2
I'm just wondering why r_$row works i.e. the buttons do not change as one but $debvar, which is an upvar alias does not.
The -variable option of widgets refers to a global variable. So that's in a different scope than the debvar in your DisplayOptions proc. They happen to have the same name, but otherwise have no relation at all.
By using the same global variable for all radiobuttons, they all work as one group. To have several groups of radiobuttons, you have to use a different global variable for each group, as you did with the r_$row version. Note that once again the r_$row local variable in your proc has no relation to the r_$row variable you use for the widgets.
You would actually be better off using a different (simpler) local variable, because if { r_$row == 0 } will always be false and it's overly complicated to get the value of a variable whose name is constructed as r_$row.
The problem is in the "shared" variable debvar. You forgot apply the same approach for each row, on this way, you can do for example ...
# set dummy variable so the radio buttons respond correctly.
set $ix [lindex $list_item 0]
upvar 0 $ix debvar_$row;# <-- Here add the row number
# Create widgets
label .lab_$row -text $lab
;#<-- Below these two lines are changed too
radiobutton .zero_$row -text $zero -variable debvar_$row -value 0 -command "SetValue $ix 0"
radiobutton .one_$row -text $one -variable debvar_$row -value 1 -command "SetValue $ix 1"
;#<-- Finally you must use a way of dereferencing in order to use each debvar
if { [set debvar_$row] == 0 } {
.zero_$row select
} else {
.one_$row select
}
I hope this help you,
Saludos!

TCL:How to create a checkbutton which selects other checkbutton

I wanted to make a master checkbutton when select it will select other checkbuttons and grey out them.
I used to set a variable for each of these buttons from master using -variable set to true for all of them but this throws error saying "invalid command name 1"
The snippet of my code looks like this.
checkbutton .top.l.all -text "Select ALL" -variable "select_all" -command { [set sanity_check 1] [set verilog_check 1] [set lef_check 1] [set lib_check 1][set apl_check 1] } -font TEMP_varwidth
checkbutton .top.l.g1 -text "File name and operating conds checks" -variable "sanity_check" -command "run_file_ops"
checkbutton .top.l.g2 -text "Syntax Checks for Verilog" -variable "verilog_check" -command "run_verilog_check"
checkbutton .top.l.g3 -text "Syntax Checks for LEF" -variable "lef_check" -command "run_lef_check"
checkbutton .top.l.g4 -text "Syntax Checks for .lib" -variable "lib_check" -command "run_lib_check"
checkbutton .top.l.g5 -text "Syntax Checks for APL" -variable "apl_check" -command "run_apl_check"
grid .top.l.all -row 1 -column 2 -sticky nw
grid .top.l.g1 -row 2 -column 2 -sticky nw
grid .top.l.g2 -row 3 -column 2 -sticky nw
grid .top.l.g3 -row 4 -column 2 -sticky nw
grid .top.l.g4 -row 5 -column 2 -sticky nw
grid .top.l.g5 -row 6 -column 2 -sticky nw
Instead of replicating all the buttons' logic in the "select all" button, just use the invoke command to programmatically click them:
checkbutton .top.l.all -text "Select ALL" \
-variable "select_all" \
-font TEMP_varwidth \
-command select_all
proc select_all {} {
foreach w {.top.l.g1 .top.l.g2 .top.l.g3 .top.l.g4 .top.l.g5} {
$w invoke
$w configure -state disabled
}
}
That will set the state for the buttons and execute their commands.
This is because you are evaluating the commands twice. Imagine it was like this (because it's essentially how it is):
checkbutton .top.l.all -text "Select ALL" -variable "select_all" -command {
[set sanity_check 1]
[set verilog_check 1]
[set lef_check 1]
[set lib_check 1]
[set apl_check 1]
} -font TEMP_varwidth
Do you think it would be correct? set evaluates first, and returns the set value 1. Then -command takes the 'command' {1 1 1 11} which is where the error occurs. The correct way to do it is:
checkbutton .top.l.all -text "Select ALL" -variable "select_all" -command {
set sanity_check 1
set verilog_check 1
set lef_check 1
set lib_check 1
set apl_check 1
} -font TEMP_varwidth
And if you want it on the single line, it becomes:
checkbutton .top.l.all -text "Select ALL" -variable "select_all" -command {set sanity_check 1; set verilog_check 1; set lef_check 1; set lib_check 1; set apl_check 1} -font TEMP_varwidth
As per comments, here's a sample to:
Make select all check all other checkbuttons when the select all checkbutton was unchecked
Execute each checkbutton's command
Grey out each checkbutton command
Reverse the visible changes from when select all is clicked if the select all checkbutton was checked (I shortened the widget names to be able to test them on my side).
checkbutton .all -text "Select ALL" -variable "select_all" -command select_all -font TEMP_varwidth
proc select_all {} {
upvar sanity_check sa verilog_check v lef_check le lib_check li apl_check a select_all se
if {$se == 1} {
# First change the checkbuttons
set sa 1
set v 1
set le 1
set li 1
set a 1
# Execute their commands
run_file_ops
run_verilog_check
run_lef_check
run_lib_check
run_apl_check
# Grey them out
.g1 configure -state disabled
.g2 configure -state disabled
.g3 configure -state disabled
.g4 configure -state disabled
.g5 configure -state disabled
} else {
# Change the checkbuttons
set sa 0
set v 0
set le 0
set li 0
set a 0
# Change them back to normal
.g1 configure -state normal
.g2 configure -state normal
.g3 configure -state normal
.g4 configure -state normal
.g5 configure -state normal
}
}

How to hide a text widget and show it later in tcl tk?

I have a problem with my display of multiple choice questions. I have a frame which shows the questions and choices above a text widget which shows if the chosen answer is correct. Yet I want to hide the text while the test is not finished.
It looks like that:
My procedures are following:
proc beginTest { number } {
startTest
.frq.txt configure -state normal
.frq.txt delete 1.0 end
set score 0
set save 0
set path Files/Tutorials/$::Tuto
set numbers { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 }
for {set i 1} {$i<=10} {incr i} {
if { $::stop == 1 } {
set answer [tk_dialog .dialog "Quit test?" "If you quit the test now, your answers will be lost. Do you want to continue?" \
question 1 "Continue test" "Quit test"]
if {$answer == 0} {
continue
} else {
break
}
} else {
set ind [expr {int(rand()*[llength $numbers])} ]
incr score [displayQuestion $path [lindex $numbers $ind] $i 10]
set numbers [lreplace $numbers $ind $ind]
}
}
.frq.txt insert end "Your score: $score/10"
.frq.txt configure -state disabled
if {[info exist user]} {
if {[lindex $::testScores $number]== "Not Taken" || [lindex $::testScores $number] < $score} {
set ::testScores [lreplace $::testScores $number $number $score]
}
}
destroy .frq.fr2
}
The following procedure called at the first line of the previous one create and define the windows, frames, text zone, etc.
proc startTest {} {
destroy .fr
#window definition
toplevel .frq
wm title .frq "Test"
wm geometry .frq 740x670+0+0
.frq configure -bg $::bgColour
# title of section
label .frq.titl
.frq.titl configure -font "arial 20" -pady 10
grid .frq.titl -column 0 -row 0 -sticky swe
.frq.titl configure -background "White"
# define the main text zone
text .frq.txt -wrap word -yscroll {.frq.vscroll set} -highlightthickness 0
.frq.txt configure -background "White" ;#"slate gray" to debug
scrollbar .frq.vscroll -orient vertical -command {.frq.txt yview}
grid .frq.txt -column 0 -row 1 -sticky snwe
grid rowconfigure .frq 1 -weight 1
grid columnconfigure .frq 0 -weight 1
grid .frq.vscroll -column 1 -row 1 -sticky snwe
.frq.txt tag configure center -justify center
.frq.txt configure -font "times 12" -state disabled
.frq.vscroll configure -orient vertical -command {.frq.txt yview}
grid .frq.txt -column 0 -row 1 -sticky snwe
.frq.txt configure -state normal
.frq.txt delete 1.0 end
#text styles
.frq.txt tag configure Normal -font "times 12"
.frq.txt tag configure subTitle -font "times 14"
.frq.txt tag configure Titlec -font "times 16" -justify "center"
.frq.txt tag configure subTitlec -font "times 14" -justify "center"
.frq.txt tag configure subTitlecu -font "times 14" -justify "center" -underline on
.frq.txt tag configure Titlecu -font "times 16" -justify "center" -underline on
.frq.txt tag configure Title -font "times 16"
.frq.txt tag configure link -foreground blue -font "times 12"
.frq.txt tag configure right -foreground "forest green"
.frq.txt tag configure wrong -foreground red
.frq.txt tag configure enhance -background "light goldenrod"
.frq.txt tag configure rightenhance -background "light goldenrod" -foreground "forest green"
.frq.txt tag bind link <Enter> ".fr.txt configure -cursor hand1"
.frq.txt tag bind link <Leave> ".fr.txt configure -cursor arrow"
#questions frame
frame .frq.fr2 -background white
grid .frq.fr2 -row 1
label .frq.lbl -relief flat -font arial -text "Question 1 of 5"
grid .frq.lbl -row 0
text .frq.fr2.txt -relief flat -background white -font "times 13" -wrap word
grid .frq.fr2.txt -columnspan 2 -row 1
.frq.fr2.txt tag configure center -justify center
grid rowconfigure .frq 1 -weight 1
checkbutton .frq.fr2.cb1 -command "choose A" -cursor hand1
grid .frq.fr2.cb1 -column 0 -row 2
label .frq.fr2.lblA -background white -font "arial 12" -pady 3
bind .frq.fr2.lblA <ButtonRelease> "choose A; .frq.fr2.cb1 toggle"
grid .frq.fr2.lblA -column 1 -row 2 -sticky w
checkbutton .frq.fr2.cb2 -command "choose B" -cursor hand1
grid .frq.fr2.cb2 -column 0 -row 3
label .frq.fr2.lblB -background white -font "arial 12" -pady 3
bind .frq.fr2.lblB <ButtonRelease> "choose B; .frq.fr2.cb2 toggle"
grid .frq.fr2.lblB -column 1 -row 3 -sticky w
checkbutton .frq.fr2.cb3 -command "choose C" -cursor hand1
grid .frq.fr2.cb3 -column 0 -row 4
label .frq.fr2.lblC -background white -font "arial 12" -pady 3
bind .frq.fr2.lblC <ButtonRelease> "choose C; .frq.fr2.cb3 toggle"
grid .frq.fr2.lblC -column 1 -row 4 -sticky w
checkbutton .frq.fr2.cb4 -command "choose D" -cursor hand1
grid .frq.fr2.cb4 -column 0 -row 5
label .frq.fr2.lblD -background white -font "arial 12" -pady 3
bind .frq.fr2.lblD <ButtonRelease> "choose D; .frq.fr2.cb4 toggle"
grid .frq.fr2.lblD -column 1 -row 5 -sticky w
frame .frq.bar
grid .frq.bar -row 2
button .frq.bar.next -text "Next question >>" -state disabled -pady 5 -borderwidth 0 -command "set ::goOn 1"
pack .frq.bar.next -padx 5 -pady 5 -side right -fill none
button .frq.bar.dp -text "Open drawing pad" -pady 5 -borderwidth 0 -command notepad
pack .frq.bar.dp -padx 5 -pady 5 -side right -fill none
button .frq.bar.calc -text "Open calculator" -pady 5 -borderwidth 0 -command calculator
pack .frq.bar.calc -padx 5 -pady 5 -side right -fill none
button .frq.bar.quit -text "Quit test" -pady 5 -borderwidth 0 -command "set ::stop 1; set ::goOn 1"
pack .frq.bar.quit -padx 5 -pady 5 -side right -fill none
}
And finally, the procedure which display the question:
proc displayQuestion {path filename ind maxind} {
set fd [open $path/$filename r]
set questionFile [split [read $fd] "\n"]
set ::goOn 0
set answers [list]
set imgFlag 0
set fd [open $path/answers/$filename r]
set goodAnswer [read $fd]
close $fd
.frq.lbl configure -text "Question $ind of $maxind"
.frq.fr2.txt configure -state normal
.frq.fr2.txt delete 1.0 end
.frq.fr2.txt insert end \n
foreach line $questionFile {
if {$line == "<image>"} {
set imgFlag 1
continue
}
if {$imgFlag == 1} {
set imgFlag 0
.frq.fr2.txt insert end " " center
.frq.fr2.txt image create end -image [image create photo -file [file join "$path/$line"]]
continue
}
if {[string match A)* $line]} {
.frq.fr2.lblA configure -text $line
lappend answers $line
continue
}
if {[string match B)* $line]} {
.frq.fr2.lblB configure -text $line
lappend answers $line
continue
}
if {[string match C)* $line]} {
.frq.fr2.lblC configure -text $line
lappend answers $line
continue
}
if {[string match D)* $line]} {
.frq.fr2.lblD configure -text $line
lappend answers $line
continue
}
.frq.fr2.txt insert end $line\n center
}
.frq.fr2.txt configure -state disabled
.frq.txt insert end [lindex $questionFile 0]\n
.frq.fr2.cb1 deselect
.frq.fr2.cb2 deselect
.frq.fr2.cb3 deselect
.frq.fr2.cb4 deselect
.frq.bar.next configure -state disabled
set ::choice 0
vwait ::goOn
switch $::choice {
A { set ind 0 }
B { set ind 1 }
C { set ind 2 }
default { set ind 3 }
}
if { $::choice == $goodAnswer} {
.frq.txt insert end "Correct answer: [lindex $answers $ind]\n\n" right
return 1
} else {
switch $goodAnswer {
A { set i 0 }
B { set i 1 }
C { set i 2 }
default { set i 3 }
}
.frq.txt insert end "Wrong answer: [lindex $answers $ind]\n\tYou should have pick [lindex $answers $i]\n\n" wrong
return 0
}
}
The widget concerned is ".frq.txt".
I have tried "pack" and "pack forget", even tried a way to use the option "-elide" but I am out of ideas.
Could you help me?
Since you're using grid to manage the contents of the .frq widget, including the .frq.txt widget, you need to use grid remove or grid forget to make the widget vanish. The difference between the two? With grid remove, the sizing metadata for the cell is remembered.
pack forget is for undoing a pack (strictly, a pack configure, though the simple pack pretends you said pack configure).

What's stored in that Tcl variable?

Pursuant to the advice given in this question I have written a little gui to take the options for a command line C program and pass them on to said C program which is already set up to process them. It displays just like I wanted.
However, I would like to verify that the values stored in the variables are correct. Getting the values to print out is giving me a lot of grief (I can't test in vivo right now due to some hardware issues). What am I missing?
Prepending the variable name with '$' gives me '$variableName' rather than the value of the variable.
Adding these variables to an array and calling array get arr is supposed to print the index and the array value; I get variable names.
I tried pathName cget option, but apparently -value isn't an option, and leaving off the option doesn't give me a list of valid options.
Here's all the code with the various things that didn't work (from option #1, which is the most straightforward way; the others were just me trying workarounds). They all produce
errors along the lines of: "can't read "::": no such variable" or "can't read
"colorimetric": no such variable".
#!/opt/ActiveTcl-8.5/bin/wish8.5
wm title . "Gretag"
ttk::frame .f -borderwidth 5 -relief sunken -padding "5 10"
# next line part of the "puts" tests at the bottom
global colorimetric
ttk::label .f.dataLabel -text "Data Type"
ttk::label .f.colorimetricLabel -text "Colorimetric"
ttk::checkbutton .f.colorimetric -onvalue "-c" -offvalue "" -command getFilename1
ttk::label .f.spectralLabel -text "Spectral"
ttk::checkbutton .f.spectral -onvalue "-s" -offvalue "" -command getFilename2
ttk::label .f.gretagNumLabel -text "Gretag #"
ttk::label .f.gretagLabel0 -text "1"
ttk::radiobutton .f.gretagRadio0 -variable gretagNum -value "/dev/ttyS0"
ttk::label .f.gretagLabel1 -text "2"
ttk::radiobutton .f.gretagRadio1 -variable gretagNum -value "/dev/ttyS1"
ttk::label .f.gretagLabel2 -text "3"
ttk::radiobutton .f.gretagRadio2 -variable gretagNum -value "/dev/ttyS2"
ttk::label .f.gretagLabel3 -text "4"
ttk::radiobutton .f.gretagRadio3 -variable gretagNum -value "/dev/ttyS3"
ttk::label .f.gretagLabel4 -text "5"
ttk::radiobutton .f.gretagRadio4 -variable gretagNum -value "/dev/ttyS4"
ttk::label .f.sampleSize -text "Sample Size"
ttk::label .f.samplex -text "X"
ttk::label .f.sampley -text "Y"
ttk::entry .f.x -textvariable x -width 5
ttk::entry .f.y -textvariable y -width 5
ttk::label .f.filterLabel -text "Filter Type"
ttk::label .f.filterLabel0 -text "D50"
ttk::radiobutton .f.filterRadio0 -variable filter -value "-d50"
ttk::label .f.filterLabel1 -text "D65"
ttk::radiobutton .f.filterRadio1 -variable filter -value "-d65"
ttk::label .f.filterLabel2 -text "Unfiltered"
ttk::radiobutton .f.filterRadio2 -variable filter -value "-U"
ttk::label .f.filterLabel3 -text "Polarized"
ttk::radiobutton .f.filterRadio3 -variable filter -value "-p"
ttk::label .f.baudLabel -text "Baud Rate"
ttk::label .f.baudLabel0 -text "4800"
ttk::radiobutton .f.baudRadio0 -variable baud -value "B4800"
ttk::label .f.baudLabel1 -text "9600"
ttk::radiobutton .f.baudRadio1 -variable baud -value "B9600"
ttk::label .f.baudLabel2 -text "19200"
ttk::radiobutton .f.baudRadio2 -variable baud -value "B19200"
ttk::label .f.baudLabel3 -text "38400"
ttk::radiobutton .f.baudRadio3 -variable baud -value "B38400"
ttk::label .f.baudLabel4 -text "57600"
ttk::radiobutton .f.baudRadio4 -variable baud -value "B57600"
ttk::button .f.submitBtn -text "Submit" -command finish
grid columnconfigure . 0 -weight 1
grid rowconfigure . 0 -weight 1
grid .f -column 0 -row 0 -columnspan 11 -rowspan 5
grid .f.dataLabel -column 0 -row 0 -sticky we
grid .f.colorimetricLabel -column 1 -row 0 -sticky e
grid .f.colorimetric -column 2 -row 0 -sticky w
grid .f.spectralLabel -column 3 -row 0 -sticky e
grid .f.spectral -column 4 -row 0 -sticky w
grid .f.gretagNumLabel -column 0 -row 1 -sticky we
grid .f.gretagLabel0 -column 1 -row 1 -sticky e
grid .f.gretagRadio0 -column 2 -row 1 -sticky w
grid .f.gretagLabel1 -column 3 -row 1 -sticky e
grid .f.gretagRadio1 -column 4 -row 1 -sticky w
grid .f.gretagLabel2 -column 5 -row 1 -sticky e
grid .f.gretagRadio2 -column 6 -row 1 -sticky w
grid .f.gretagLabel3 -column 7 -row 1 -sticky e
grid .f.gretagRadio3 -column 8 -row 1 -sticky w
grid .f.gretagLabel4 -column 9 -row 1 -sticky e
grid .f.gretagRadio4 -column 10 -row 1 -sticky w
grid .f.sampleSize -column 0 -row 2 -sticky we
grid .f.samplex -column 1 -row 2 -sticky e
grid .f.x -column 2 -row 2 -sticky w
grid .f.sampley -column 3 -row 2 -sticky e
grid .f.y -column 4 -row 2 -sticky w
grid .f.filterLabel -column 0 -row 3 -sticky we
grid .f.filterLabel0 -column 1 -row 3 -sticky e
grid .f.filterRadio0 -column 2 -row 3 -sticky w
grid .f.filterLabel1 -column 3 -row 3 -sticky e
grid .f.filterRadio1 -column 4 -row 3 -sticky w
grid .f.filterLabel2 -column 5 -row 3 -sticky e
grid .f.filterRadio2 -column 6 -row 3 -sticky w
grid .f.filterLabel3 -column 7 -row 3 -sticky e
grid .f.filterRadio3 -column 8 -row 3 -sticky w
grid .f.baudLabel -column 0 -row 4 -sticky we
grid .f.baudLabel0 -column 1 -row 4 -sticky e
grid .f.baudRadio0 -column 2 -row 4 -sticky w
grid .f.baudLabel1 -column 3 -row 4 -sticky e
grid .f.baudRadio1 -column 4 -row 4 -sticky w
grid .f.baudLabel2 -column 5 -row 4 -sticky e
grid .f.baudRadio2 -column 6 -row 4 -sticky w
grid .f.baudLabel3 -column 7 -row 4 -sticky e
grid .f.baudRadio3 -column 8 -row 4 -sticky w
grid .f.baudLabel4 -column 9 -row 4 -sticky e
grid .f.baudRadio4 -column 10 -row 4 -sticky w
grid .f.submitBtn -column 1 -row 5 -columnspan 7 -sticky we
foreach w [winfo children .f] {grid configure $w -padx 5 -pady 5}
focus .f.colorimetric
.f.colorimetric state selected
.f.filterRadio1 state selected
.f.baudRadio1 state selected
bind . <Return> {finish}
proc getFilename1 {} {
set filename1 [tk_getSaveFile]
}
proc getFilename2 {} {
set filename2 [tk_getSaveFile]
}
proc finish {} {
.f.x insert 0 "-x"
.f.y insert 0 "-y"
# Pick one
# puts $colorimetric
# puts colorimetric
# puts "$colorimetric"
# puts $::colorimetric
# puts .f.colorimetric
# puts $.f.colorimetric
# puts $::.f.colorimetric
# puts "$::colorimetric"
exec ./gretag .f.colorimetric filename1 .f.spectral filename2 .f.gretagNum .f.x .f.y .f.filter .f.baud
}
Edit:
I've posted all the code rather than just part, and in the next to last line are the various syntaxes from option #1 that I've tried in order to view the values of the variables before they're passed to the next program. None of these are working and I don't understand why or how to fix it. I'm hoping another set of eyes will catch what's wrong.
Variable Basics
As others have pointed out, the confusing to $ or not to $ notation can be simplified by the following rule.
var is a reference to the variable itself, not its value
$var yields the value held in the variable
It can become a little more confusing when you start to think of everything in Tcl as a string (it's really not, but close enough), so you can store the name of one variable in another and restore its value by reference.
% set foo "hi"
hi
% set bar "foo"
foo
% set $foo
can't read "hi": no such variable
% set $bar
hi
Here the notation set $foo is evaluated in step - first $foo yields its value hi and then the set expression (when run with no third argument) attempts to return the value held in the variable hi. This fails. The notation set $bar takes the same steps but this time set can operate on the value of bar, which is foo, and thus returns the value of foo which is hi. (link to "set" API)
Initialization
One problem you have in this script is initialization. In Tcl variables don't exist until they're assigned a value. That's clearly why trying to set $foo above didn't work, because there was no variable hi.
At the top of your script you attempt to declare a variable with,
global colorimetric
which doesn't work, because you are already operating in global scope. Global "has no effect unless executed in the context of a proc body." (link to "global" API) You actually have to use a set command to initialize the variable. This is why none of your attempts to print colorimetric in proc finish worked.
Scope
The other problem you have in this script is scope, particularly with mixing global and procedural/local scope. You're correct that, had you initialized colorimetric correctly then the code,
puts $::colorimetric ;# print the value of the global variable colorimetric
would have worked. Another way to achieve this is with,
global colorimetric ;# reference a global variable into the local scope
puts $colorimetric ;# print the value of colorimetric in the local scope
My Solution
I'd like to present my solution. I admit that I've moved a lot of code around, and I will go into a short explanation of what changes I implemented to make it more concise.
#!/usr/bin/env wish
# --- default configuration --- #
array set CONF {
colorimetric "-c"
spectral ""
cfilename "/path/to/defaultCI.txt"
sfilename ""
x 0
y 0
gretagnum "/dev/ttyS0"
filter "-d65"
baud "B9600"
}
# --- build the interface --- #
wm title . "Gretag"
ttk::frame .f -borderwidth 5 -relief sunken -padding "5 10"
grid columnconfigure . 0 -weight 1
grid rowconfigure . 0 -weight 1
grid .f
ttk::label .f.dataLabel -text "Data Type: "
foreach {dtname dttag dtfile} {
colorimetric "-c" cfilename
spectral "-s" sfilename
} {
lappend mygrid [
ttk::checkbutton .f.$dtname -text [string totitle $dtname] \
-variable CONF($dtname) -onvalue $dttag -offvalue "" \
-command [list getFilename $dtname $dttag $dtfile ]
]
}
grid .f.dataLabel {*}$mygrid -sticky w ; set mygrid { }
ttk::label .f.gretagNumLabel -text "Gretag #: "
for {set tty 0} {$tty < 5} {incr tty} {
lappend mygrid [
ttk::radiobutton .f.gretagRadio$tty -text [expr $tty + 1] \
-variable CONF(gretagnum) -value "/dev/ttyS$tty"
]
}
grid .f.gretagNumLabel {*}$mygrid -sticky w ; set mygrid { }
ttk::label .f.sampleSize -text "Sample Size: "
ttk::label .f.samplex -text "X"
ttk::label .f.sampley -text "Y"
ttk::entry .f.x -textvariable CONF(x) -width 5
ttk::entry .f.y -textvariable CONF(x) -width 5
grid .f.sampleSize .f.samplex .f.x .f.sampley .f.y
ttk::label .f.filterLabel -text "Filter Type: "
foreach {ftname ftval} {
D50 "-d50"
D65 "-d65"
Unfiltered "-U"
Polarized "-P"
} {
lappend mygrid [
ttk::radiobutton .f.filterRadio$ftname -text $ftname \
-variable CONF(filter) -value $ftval
]
}
grid .f.filterLabel {*}$mygrid -sticky w ; set mygrid { }
ttk::label .f.baudLabel -text "Baud Rate: "
foreach {baud} {
4800 9600 19200 38400 57600
} {
lappend mygrid [
ttk::radiobutton .f.baudRadio$baud -text $baud \
-variable CONF(baud) -value "B$baud"
]
}
grid .f.baudLabel {*}$mygrid -sticky w ; set mygrid { }
ttk::button .f.submitBtn -text "Submit" -command submit
grid .f.submitBtn -columnspan 6 -sticky we
foreach w [winfo children .f] {
grid configure $w -padx 5 -pady 5
}
focus .f.colorimetric
bind . <Return> submit
# --- callbacks --- #
proc getFilename {type tag file} {
global CONF
if {$CONF($type) eq $tag} {
set CONF($file) [tk_getOpenFile]
if {$CONF($file) eq ""} { .f.$type invoke }
} else {
set CONF($file) ""
}
}
proc submit { } {
global CONF
exec ./gretag $CONF(colorimetric) $CONF(cfilename) \
$CONF(spectral) $CONF(sfilename) $CONF(gretagnum) \
$CONF(x) $CONF(y) $CONF(filter) $CONF(baud)
}
Discussion of Changes
1. The first changes I made were to use the -text options on the ttk::checkbutton and ttk::radiobutton. Granted, using an extra label for these allows you to place the text before the button, but doing so is non-standard and requires more code.
ttk::label .f.colorimetricLabel -text "Colorimetric"
ttk::checkbutton .f.colorimetric -onvalue "-c" -offvalue "" -command getFilename1
becomes
ttk::checkbutton .f.colorimetric -text "Colorimetric" -onvalue "-c" -offvalue "" -command getFilename1
2. Next I used the similarities between these two checkbuttons to abstract the creation into a foreach. (I do this all the time in my Tcl code for work.) This generates much easier code to read and allows you to add/remove/swap names and tags for the widgets. It results in slightly more but much more versitile code.
ttk::checkbutton .f.colorimetric -text "Colorimetric" -onvalue "-c" -offvalue "" -command getFilename1
ttk::checkbutton .f.colorimetric -text "Spectral" -onvalue "-s" -offvalue "" -command getFilename2
becomes
foreach {dtname dttag dtcommand} {
colorimetric "-c" getFilename1
spectral "-s" getFilename2
} {
ttk::checkbutton .f.$dtname -text [string totitle $dtname] -onvalue $dttag -offvalue "" -command $dtcommand
}
3. The next change was to merge your getFilename1 and getFilename2 into a single getFilename procedure. We can pass arguments into this function to determine who is calling it. I use the list command to generate the call for this new function. (link to "list" API)
I also started to combine your grid commands into the widget code itself. Here mygrid keeps a list of what needs to be gridded per line in the GUI and then is evaluated at the end of each section to propagate the GUI on the fly. (link to "grid" API)
The previous code gets its final revision and becomes,
foreach {dtname dttag dtfile} {
colorimetric "-c" cfilename
spectral "-s" sfilename
} {
lappend mygrid [
ttk::checkbutton .f.$dtname -text [string totitle $dtname] -variable CONF($dtname) -onvalue $dttag -offvalue "" -command [list getFilename $dtname $dttag $dtfile ]
]
}
Then the grid command can be evaluated and the mygrid variable cleared after every use!
4. If you've been paying attention I also added a -variable option to your ttk::checkbutton and at this point started storing the button state in a global variable CONF. This is a big change.
Tk loves to pollute your global namespace and it's good practice to fight back. I usually put all of my configuration state in a global array, and set that right up top of the code so that anyone can come in and change the default state of my code, without digging into it or doing search/replace calls or anything like that. Just good practice, so wherever you had a variable I moved it into CONF and moved CONF up top.
array set CONF {
colorimetric "-c"
spectral ""
cfilename "/path/to/defaultCI.txt"
sfilename ""
x 0
y 0
gretagnum "/dev/ttyS0"
filter "-d65"
baud "B9600"
}
5. Next I propagated these changes throughout your code. Almost all of the widget creation was susceptible to these revisions. With respect to the widget creation this sometimes made independent code sections larger. But it also allowed me to remove your entire grid section, merging this code up into the widget code as I've discussed, greatly decreasing the size and clutter of your code at the added expense of complexity.
6. The final changes I made were to your function code. You have a couple of minor bugs in your getFilename1 and getFilename2 code. The first bug was that you want to call tk_getOpenFile because I gather you are only grabbing an existing file name to pass it to gretag. (link to 'tk_getOpenFile' API) If you use tk_getOpenFile the dialog will make sure the file exists.
The second bug in getFilename1 is that the dialog has a Cancel button, and if the user clicks this cancel button the dialog returns an empty string. In this case you have to un-check the ttk::checkbutton and you have to unset the CONF(colorimetric) variable. Or more correctly you have to set CONF(colorimetric) to the button's -offvalue. You can do both of these at once by sending a click event to the current button.
proc getFilename1 {} {
set filename1 [tk_getSaveFile]
}
becomes
proc getFilename {type tag file} {
global CONF
if {$CONF($type) eq $tag} {
set CONF($file) [tk_getOpenFile]
if {$CONF($file) eq ""} { .f.$type invoke }
} else {
set CONF($file) ""
}
}
In your finish function I renamed the function to submit (sorry) and rewrote it to make use of the new CONF variable.
The Answer
Of course most of this was unnecessary. I wanted to give you some interesting Tcl/Tk code to think about while at the same time solving your problem. At this point we should have the vocabulary to answer your question, though.
The reason your variables weren't printing out was because of initialization and scope. You should always use a -variable or -textvariable on widgets that you need to reference later. I generally initialize my referenced variables before building their containing widgets. So at the top of your file if you had done,
set colorimetric "-c"
ttk::checkbutton .f.colorimetric -variable colorimetric [...]
Then you would have been able to do, in the finish function,
puts $::colorimetric
You have not assigned any variable to the colorimetric checkbutton.
Add -variable colorimetric to the checkbutton, and then in finish
you can use:
puts $::colorimetric
Also, set ::colorimetric first to select your default value. That
is easier than trying to mess with the state of the widget.
I see that the values colorimetric can have are "" and "-c" so
I assume you will use that value in the exec line.
Beware that [exec something yada $::colorimetric something] will
probably not work then. You'll probably need {*}$::colorimetric in the
exec line to make the argument disappear if it is empty.
Here's a little tcl snippet - run from tclsh or wish
[nigel#rose ~]$ wish
% set foo /dev/ttys0
/dev/ttys0
% puts $foo
/dev/ttys0
% puts "$foo"
/dev/ttys0
% puts [$foo]
invalid command name "/dev/ttys0"
% puts ($foo)
(/dev/ttys0)
% puts {$foo}
$foo
%
Quoting in Tcl:
"" (double quotes): Evaluate substitutions ($variable)
{} {Squiggly brackets): Treat the entire string as a literal with no substitution
[] (Square brackets): Execute the string as a command with substitution
As an alternative you could pop up the diagnostic in a dialog box:
% set mb [tk_messageBox -message "Port is $foo" -type ok -icon info]
ok
%
At your "# Just here" comment, try adding
puts $::gretagNum
:: signifies a global variable, and the -variable option to widgets
are always global.
I'm not sure what you want to do, put if you end put printing the variable name and not the variable content, use the set command as function:
set content "hello"
set blah content
if you do:
puts $blah
.. you get the content of the blah variable, which is content.
To get the content of the variable content via blah, use the following:
puts [set $blah]
Just remember this rule and you will always get it right:
$foo is shorthand for [set foo]
Try rewriting your code with [set foo] and it will work.
In particular,
$$foo ;# not what you think
is replaced by
[set [set foo]] ;# does what you think