早上好
我正在运行以下代码
foreach rs_lb {kl15_lb din1_lb din2_lb din3_lb din4_lb \
dinnc_lb ain1_lb ain2_lb ain3_lb ain4_lb a_lb \
b_lb u_lb v_lb w_lb sin_lb cos_lb th1_lb th2_lb hvil_lb} \
rs_lb_txt {KL15 DIN1 DIN2 DIN3 DIN4 DINNC AIN1 AIN2 AIN3 AIN4 \
A B U V W SIN COS TH1 TH2 HVIL} \
rs_lb_rw {0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9} \
rs_lb_cm {0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2} \
rs_cb {kl15_cb din1_cb din2_cb din3_cb din4_cb dinnc_cb ain1_cb \
ain2_cb ain3_cb ain4_cb a_cb \
b_cb u_cb v_cb w_cb sin_cb cos_cb th1_cb th2_cb hvil_cb} \
rs_cb_rw {0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9} \
rs_cb_cm {1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3} \
ds_out_i {0 0 2 0 4 0 6 0 8 0 10 0 12 0 14 0 16 0 18 0 20 0 \
22 0 24 0 26 0 28 0 30 0 32 0 34 0 36 0 38 0} \
{
label .rs.$rs_lb -text "$rs_lb_txt"
checkbutton .rs.$rs_cb -variable $rs_cb -command {
if {$rs_cb} {
set ds_out($ds_out_i) 1
set ds_out([expr $ds_out_i + 1]) 1
} else {
set ds_out($ds_out_i) 0
set ds_out([expr $ds_out_i + 1]) 0
}
}
grid .rs.$rs_lb -row $rs_lb_rw -column $rs_lb_cm
grid .rs.$rs_cb -row $rs_cb_rw -column $rs_cb_cm
}
我得到了错误:
父窗口中已经存在窗口名称“”
当我单击复选框时,出现应用程序错误:
期望的布尔值,但获得了“” 预期的布尔值,但得到“” 在执行时 “如果{$ rs_cb} { 设置ds_out($ ds_out_i)1 设置ds_out([expr $ ds_out_i + 1])1 }其他{ 设置ds_out($ ds_out_i)0 设置ds_out([expr $ ds_out_i + ...“ 从内部调用 “ .rs.u_cb调用” (“上级”正文行1) 从内部调用 “上级#0 [列出$ w调用]” (过程“ tk :: ButtonUp”第24行) 从内部调用 “ tk :: ButtonUp .rs.u_cb” (命令绑定到事件)
有人可以告诉我为什么会这样吗?
答案 0 :(得分:2)
window name "" already exists in parent
是因为提供ds_out_i
的列表比提供所有其他变量的列表更长(两倍!)。 foreach
一直进行下去,直到遍历每个项目的所有元素为止,然后将其列表已被耗尽的变量分配给空字符串。
我猜想您想对当前提供ds_out_i
的列表使用双变量列表迭代,或者更有可能遍历成对的列表。 (请注意,这会使您的回调代码进一步中断;稍后,我会解决这个问题。)
…
ds_out_i {{0 0} {2 0} {4 0} {6 0} {8 0} {10 0} {12 0} {14 0} {16 0} {18 0} {20 0} \
{22 0} {24 0} {26 0} {28 0} {30 0} {32 0} {34 0} {36 0} {38 0}} \
…
您的另一个错误是因为您当前在-command
选项(到checkbutton
)中使用了复杂的嵌入式脚本。 不要那样做! 。这真的很难。强烈建议的方法是创建一个小的帮助程序,然后使-command
选项成为调用该过程并由list
命令生成的简单脚本。
我们是认真的。如果我能使那条闪烁的旗帜,我会的。做对很难,对错也很容易。使用帮助程序非常容易正确。这就是您的外观。
proc rs_checkbutton_callback {varname index} {
# "parse" the arguments
global ds_out; # We're working with a global variable here
upvar "#0" $varname rs_cb; # Alias the named global variable as rs_cb
lassign $index a b; # This splits the two-part ds_out_i into two variables, a and b
if {$rs_cb} {
set ds_out($a) 1
set ds_out($b) 1
} else {
set ds_out($a) 0
set ds_out($b) 0
}
}
…
checkbutton .rs.$rs_cb -variable $rs_cb \
-command [list rs_checkbutton_callback $rs_cb $ds_out_i]
我不确定该回调过程是否在执行您真正想要的操作。相反,这样做可能更好:
proc rs_checkbutton_callback {varname index} {
# "parse" the arguments
global ds_out; # We're working with a global variable here
upvar "#0" $varname rs_cb; # Alias the named global variable as rs_cb
lassign $index a b; # This splits the two-part ds_out_i into two variables, a and b
if {$rs_cb} {
set ds_out([list $a $b]) 1
set ds_out([list $a [expr {$b + 1}]) 1
} else {
set ds_out([list $a $b]) 0
set ds_out([list $a [expr {$b + 1}]) 0
}
}
答案 1 :(得分:0)
一个好的编程原则是Occam的Razor,即“实体不必不必要地相乘”。您可以从简单的名称列表中创建小部件路径和复选框标签:
foreach name {foo bar baz} {
lappend lbnames ${name}_lb
lappend cbnames ${name}_cb
lappend texts [string toupper $name]
}
list $lbnames $cbnames $texts
# => {foo_lb bar_lb baz_lb} {foo_cb bar_cb baz_cb} {FOO BAR BAZ}
在这种情况下,最好将名称列表分成两个相等的部分:
set names1 {
kl15 din1 din2 din3 din4 dinnc ain1 ain2 ain3 ain4
}
set names2 {
a b u v w sin cos th1 th2 hvil
}
然后我们就可以开始创建小部件了。不幸的是,我无法弄清楚命令的工作方式,但是在这里集成回调调用也很容易。由于我们并行创建小部件的列,因此无需跟踪grid
行和列:
toplevel .rs
foreach name1 $names1 name2 $names2 {
grid \
[label .rs.${name1}_lb -text [string toupper $name1]] \
[checkbutton .rs.${name1}_cb -variable ${name1}_cb -command [list ...]] \
[label .rs.${name2}_lb -text [string toupper $name2]] \
[checkbutton .rs.${name2}_cb -variable ${name2}_cb -command [list ...]]
}
这样,设置小部件数组变得更加容易,代码也更加清晰。
顺便说一句,您知道您可以在checkbutton
小部件中设置标签吗?
foreach name1 $names1 name2 $names2 {
grid \
[checkbutton .rs.${name1}_cb -text [string toupper $name1] -variable ${name1}_cb -command [list ...]] \
[checkbutton .rs.${name2}_cb -text [string toupper $name2] -variable ${name2}_cb -command [list ...]] \
-sticky w
}