根据这个问题中给出的建议,我写了一个小gui来获取命令行C程序的选项,并将它们传递给已经设置来处理它们的C程序.它显示就像我想要的那样.
但是,我想验证存储在变量中的值是否正确. 获得打印出来的价值让我感到非常悲痛(由于某些硬件问题,我现在无法在体内进行测试).我错过了什么?
在变量名前面添加'$'会给我'$ variableName'而不是变量的值.
将这些变量添加到数组并调用array get arr
应该打印索引和数组值; 我得到变量名称.
我尝试了pathName cget
选项,但显然-value
不是一个选项,并且不使用该选项不会给我一个有效选项列表.
以下是所有代码中包含各种不起作用的代码(来自选项#1,这是最直接的方式;其他代码只是我尝试解决方法).它们都产生错误:"无法读取"::":没有这样的变量"或"无法读取"比色":没有这样的变量".
#!/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 .{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 }
编辑: 我发布了所有代码而不仅仅是部分代码,并且在倒数第二行中是来自选项#1的各种语法,我试过这些语法是为了在变量传递给它之前查看变量的值下一个节目.这些都不起作用,我不明白为什么或如何解决它.我希望另一双眼睛能抓住什么是错的.
正如其他人所指出的那样,以下规则可以简化$ $或$ $符号的混淆.
var是对变量本身的引用,而不是对其值的引用
$ var产生变量中保存的值
当你开始将Tcl中的所有内容都想象成一个字符串(它确实不是,但足够接近)时,它会变得有点混乱,因此您可以将一个变量的名称存储在另一个变量中并通过引用恢复其值.
% set foo "hi" hi % set bar "foo" foo % set $foo can't read "hi": no such variable % set $bar hi
这里的符号set $foo
是在步骤中计算的 - 首先$foo
得到它的值hi
,然后set
表达式(当没有第三个参数运行时)尝试返回变量中保存的值hi
.这失败了.符号set $bar
采用相同的步骤,但这个时间set
能上的值进行动作bar
,这是foo
,因而返回的值foo
是hi
.(链接到"set"API)
您在此脚本中遇到的一个问题是初始化.在Tcl中,变量在被赋值之前不存在.这显然是为什么尝试set $foo
上面的方法不起作用,因为没有变量hi
.
在脚本的顶部,您尝试使用以下方式声明变量:
global colorimetric
这不起作用,因为您已经在全球范围内运营.全局"除非在proc主体的上下文中执行,否则无效." (链接到"global"API)您实际上必须使用set
命令来初始化变量.这就是为什么你没有尝试打印colorimetric
的原因proc finish
.
此脚本中的另一个问题是范围,特别是混合全局和过程/本地范围.你是正确的,如果你colorimetric
正确地初始化了代码,
puts $::colorimetric ;# print the value of the global variable colorimetric
本来会有用的.实现这一目标的另一种方法是,
global colorimetric ;# reference a global variable into the local scope puts $colorimetric ;# print the value of colorimetric in the local scope
我想提出我的解决方案.我承认我已经移动了很多代码,我将简要解释一下我实施了哪些更改以使其更简洁.
#!/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 .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) }
1.我所做的第一个变化是使用-text
上的选项ttk::checkbutton
和ttk::radiobutton
.当然,为这些使用额外的标签允许您将文本放在按钮之前,但这样做是非标准的并且需要更多代码.
ttk::label .f.colorimetricLabel -text "Colorimetric" ttk::checkbutton .f.colorimetric -onvalue "-c" -offvalue "" -command getFilename1
变
ttk::checkbutton .f.colorimetric -text "Colorimetric" -onvalue "-c" -offvalue "" -command getFilename1
2.接下来,我使用这两个复选框之间的相似性将创作抽象为foreach.(我一直在我的Tcl代码中执行此操作.)这会生成更容易读取的代码,并允许您为小部件添加/删除/交换名称和标记.它导致稍微多一些但更多的代码.
ttk::checkbutton .f.colorimetric -text "Colorimetric" -onvalue "-c" -offvalue "" -command getFilename1 ttk::checkbutton .f.colorimetric -text "Spectral" -onvalue "-s" -offvalue "" -command getFilename2
变
foreach {dtname dttag dtcommand} { colorimetric "-c" getFilename1 spectral "-s" getFilename2 } { ttk::checkbutton .f.$dtname -text [string totitle $dtname] -onvalue $dttag -offvalue "" -command $dtcommand }
3.下一个变化是将您getFilename1
和合并getFilename2
到一个getFilename
程序中.我们可以将参数传递给这个函数来确定谁在调用它.我使用该list
命令生成对此新函数的调用.(链接到"list"API)
我也开始将你的grid
命令组合到widget代码本身.这里mygrid
列出了GUI中每行需要网格化的内容,然后在每个部分的末尾进行评估,以便即时传播GUI.(链接到"grid"API)
之前的代码得到了最终版本,并成为,
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
可以评估命令并mygrid
在每次使用后清除变量!
4.如果你一直在关注,我还-variable
为你添加了一个选项,ttk::checkbutton
此时开始将按钮状态存储在全局变量中CONF
.这是一个很大的变化.
Tk喜欢污染你的全局命名空间,这是反击的好习惯.我通常将我的所有配置状态放在一个全局数组中,并将其设置在代码顶部,以便任何人都可以进入并更改我的代码的默认状态,而无需深入研究或执行搜索/替换调用或类似那.这是一个很好的练习,所以无论你有变量,我都会把它CONF
移到CONF
顶部.
array set CONF { colorimetric "-c" spectral "" cfilename "/path/to/defaultCI.txt" sfilename "" x 0 y 0 gretagnum "/dev/ttyS0" filter "-d65" baud "B9600" }
5.接下来,我在整个代码中传播了这些更改.几乎所有的小部件创建都容易受到这些修订的影响.关于小部件创建,这有时使独立的代码部分更大.但它也允许我删除整个网格部分,将这些代码合并到我讨论过的小部件代码中,大大减少了代码的大小和混乱,增加了复杂性.
6.我所做的最终更改是您的功能代码.您getFilename1
和getFilename2
代码中有一些小错误.第一个错误是你要打电话,tk_getOpenFile
因为我收集你只是抓取现有的文件名来传递给它gretag
.(链接到'tk_getOpenFile'API)如果使用tk_getOpenFile
该对话框,将确保该文件存在.
第二个错误getFilename1
是对话框有一个Cancel
按钮,如果用户单击此取消按钮,对话框将返回一个空字符串.在这种情况下,你必须取消检查ttk::checkbutton
,你必须取消设置CONF(colorimetric)
变量.或者更准确地说,你必须设置CONF(colorimetric)
按钮-offvalue
.您可以通过向当前按钮发送单击事件来同时执行这两项操作.
proc getFilename1 {} { set filename1 [tk_getSaveFile] }
变
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) "" } }
在你的finish
函数中,我将函数重命名为submit
(抱歉)并重写它以使用新CONF
变量.
当然,大多数情况都是不必要的.我想给你一些有趣的Tcl/Tk代码来思考,同时解决你的问题.在这一点上,我们应该有词汇来回答你的问题.
您的变量未打印出来的原因是初始化和范围.您应该始终使用稍后需要引用的小部件-variable
或-textvariable
小部件.我通常在构建包含小部件之前初始化我引用的变量.所以,如果你做了,你的文件的顶部,
set colorimetric "-c" ttk::checkbutton .f.colorimetric -variable colorimetric [...]
那么你可以在finish
函数中做到
puts $::colorimetric