具有多个命令行参数的按钮

时间:2015-11-20 11:32:44

标签: tcl tk

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
    }

3 个答案:

答案 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。你有一些可能性:

  1. 按顺序执行两个proc。您只需创建一个执行两者的函数:

    proc both_exec {seconds} {
    
        progressbar $seconds
        run_structural_comparision
    }
    
  2. 第二种方法是使用bind命令添加函数:

    bind .b <Button-1> [list progressbar 300]
    bind .b <Button-1> + [list run_structural_comparision]
    
  3. 第三种方式(编码越难但并行执行而不是一个接一个地执行)是创建一个合并两个函数代码的新proc。这样做,您可以在执行比较之间更新进度条,并且没有完成的进度条并开始比较操作。