如何在 tcl / tk 中开发对话计,通过移动它获取循环值并在比例小部件中更新

How to develop dialog gauge in tcl / tk that gets loop value and updates in scale widget by moving it

我正在尝试制作一个进度条对话框,例如 GNU/Linux Xdialog --gauge

显然您应该得到一个值,该值会不时更新 'one second'。

这个增量是通过一个 for 循环完成的,该循环已经预先配置为提供累进计数。

根据我所做的测试,我对 tcl/tk 的了解程度是这样的:

proc bar { pos } {
global txt
set txt $pos
}

set btn [button .btn -text "Play" -relief groove -command { bar $pos }]

scale .scl -length 200 -width 5 -orient horizontal -from 0 -to 100 -resolution 1 -variable value -sliderlength 5 -sliderrelief flat -activebackground blue -command { bar } -showvalue 0

label .lbl -textvariable txt -width 5

grid $btn -row 0 -column 0
grid .scl -row 0 -column 1
grid .lbl -row 0 -column 2

global value
for {set value 0} {$value < 10} {incr value} {  
after 1000; # delay
if {$value < 10} { puts "Number: $value" }
bind . "$btn invoke"
}

这行得通,所以在控制台中..它不显示表单,window 比例小部件正在缓慢移动。所以我需要最有经验的人的帮助,我怎样才能得到这个?

我创建了一个多帧动画以获得更好的创意。看:

问题是你有一个同步延迟循环。您需要一个异步的,以便可以处理显示更新。

coroutine countUp apply {{} {  # <<< launch coroutine for asynchronous state
    global value
    for {set value 0} {$value < 10} {incr value} {
        after 1000 [info coroutine]; yield; # <<< suspend coro for 1 second
        puts "Number: $value"
    }
}}

(没有协程也可以写出这段代码,但是代码不太清晰。)

并且建议您在需要进度条时使用ttk::progressbar。更正用户视觉提示等。

命令

after 1000; # delay

只是阻止,不允许 Tcl/Tk 进行任何处理。 由于您的程序还没有进入事件循环,所以不会显示任何内容。

在某些情况下,最终替换 'after' 命令的任何代码都将具有 允许屏幕更新的延迟。

# don't put the bind inside the for loop
# is this even needed?
bind . "$btn invoke"

set ::waitvar 0
for {set value 0} {$value < 10} {incr value} {  
   # a simplistic solution for purposes of this example
   # vwait cannot be nested, and should be used very carefully or not at all.
   after 1000 set ::waitvar 1
   vwait ::waitvar
   set ::waitvar 0
}

更好的方法应该是:

  proc updateScale { v } {
     global value
     set value $v
  }

  proc checkProgress { } {
     # query the progress of the task and see how far along it is
     set progress [queryProgress]
     updateScale $progress
     after 1000 [list checkProgress]
  }

  # schedule a call to checkProgress to start things off.
  after 1000 [list checkProgress]
  # and now the program enters the event loop