tcl中的按钮可以链接到多个命令行参数吗? 我有一个代码,当单击一个按钮时运行,一个时间以秒为单位的进度条代码也与它相关联,并且应该在按下该按钮时同时启动。 我使用{}将两个proc作为命令放在按钮命令参数中,但是它失败并显示错误。
代码段
button .b -image $p -command {progressbar 300 run_structural_comparision}
proc progressbar {seconds} {
ttk::progressbar .pg -orient horizontal -mode determinate -maximum $seconds
pack .pg -side left
update idletasks
# Do some real work here for $seconds seconds
for {set i 0} {$i < $seconds} {incr i} {
after 1000; # Just waiting in this example, might as well do something useful here
.pg step; # After some part of the work, advance the progressbar
update idletasks; # Needed to update the progressbar
}
# Done, clean up the dialog and progressbar
}
proc run_structural_comparision {} {
type_run
global ENTRYfilename ENTRYfilename2 curDIR curDIR2 typep reflib compLib rundir hvt_verilog logfile
set path [concat $reflib $compLib]
## set path [concat $ENTRYfilename $ENTRYfilename2]
puts $path
set str "compare_structure -overlap_when -type {timing constraint} -report compare_structure_"
set trt ".txt"
set structure [concat [string trim $str][string trim $typep][string trim $trt] $path]
puts $structure
puts $rundir
cd $rundir
set filename [concat "compare_structure_" $typep ".tcl"]
if {[ file exists $rundir/$filename] == 1 } {
exec rm -rf $rundir/compare_structure_$typep.tcl
}
答案 0 :(得分:2)
按钮的-command
回调是一个Tcl脚本。它将在堆栈的全局级别进行评估。如果要运行两个命令,可以在其中放置一个脚本来运行这两个命令:
button .b -command { command_1; command_2 }
这将按顺序运行 。 Tcl自然是单线程的,因为它是迄今为止最容易使用的编程模型。可以通过回调来制作可以同时执行多项操作的代码(这就是Tk的工作原理,就像地球上几乎所有其他GUI一样),但实际上你一次只做一件事。
您需要的核心是在后台运行需要很长时间的程序,以便您可以监视它并继续更新GUI。遗憾的是,这不是一个微不足道的话题,正确的答案将取决于究竟发生了什么。
最简单的技术之一是CPU绑定处理在子进程中完成。在这种情况下,您可以通过管道运行子进程并设置fileevent
以在生成输出或程序终止时为您提供通知回调。 Tcl非常善于这种事情;许多语言拥有的东西作为非常先进的技术在使用Tcl时感觉很自然,因为已经对如何使I / O回调很好地进行了大量的思考。
如果它处于进程中且长时间运行而没有回调的机会,事情会变得更加复杂,因为您必须在不同的线程中进行处理和GUI更新。如果你已经完成了所有设置,但这可能需要对你的程序进行大量的重新设计(因为通常Tcl中的线程彼此之间的隔离非常强烈),这不是太难。
答案 1 :(得分:1)
最简单的方法是创建一个调用这两个函数的过程。如果你想要:
update idletasks
您可以在立即按钮处理程序命令字符串中放置多个调用,但它很快就会变得复杂。但简而言之,使用分号分隔两个命令。
如果after
应被视为&#34;代码异味&#34;,则使用。即:避免它。在这种情况下,在进度条功能中,设置栏然后只需调用rm -rf
调用的其他内容来更新进度状态。
我怀疑你的file delete
可能没有做你想做的事。它可能会锁定接口,因为在命令完成之前你什么也得不到。更好的是编写一个函数来遍历目录树并使用after
删除文件,然后您可以随时提升进度事件并通过再次使用function cloneObject(obj) {
var ret = {};
var cloneArray = function(arr) {
var ret = [];
for (var i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
cloneArray(arr[i]);
} else {
ret[i] = arr[i];
}
}
return ret;
}
obj = obj || {}
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
// In case of property is an array.
if (Array.isArray(obj[i])) {
ret[i] = cloneArray(obj[i]);
} else if (typeof obj[i] == 'object') {
// Recursive call in case of sub objects.
ret[i] = cloneObj(obj[i]);
} else if (typeof obj[i] == 'function') {
ret[i] = obj[i].bind(ret);
} else {
// In case of primitive datatypes
ret[i] = obj[i];
}
}
}
// Return a reference to the new object.
return ret;
}
将处理分解为块来保持UI活跃
答案 2 :(得分:1)
您无法在同一时间执行两个proc
。你有一些可能性:
按顺序执行两个proc
。您只需创建一个执行两者的函数:
proc both_exec {seconds} {
progressbar $seconds
run_structural_comparision
}
第二种方法是使用bind
命令添加函数:
bind .b <Button-1> [list progressbar 300]
bind .b <Button-1> + [list run_structural_comparision]
第三种方式(编码越难但并行执行而不是一个接一个地执行)是创建一个合并两个函数代码的新proc
。这样做,您可以在执行比较之间更新进度条,并且没有完成的进度条并开始比较操作。