Tcl TK spinbox进入了更新GUI的无限周期

Tcl TK spinbox进入了更新GUI的无限周期,tcl,tk,reentrancy,spinbox,Tcl,Tk,Reentrancy,Spinbox,我无法修复spinbox的奇怪行为。具体地说,我需要在更改spinbox的值时通过-command和update更新GUI 稍微简化的代码如下所示: package require Tk set sv 1 ttk::spinbox .sp -from 1 -to 9 -textvariable ::sv \ -command { after 50 ;# some processing imitated puts [incr :

我无法修复
spinbox
的奇怪行为。具体地说,我需要在更改spinbox的值时通过
-command
update
更新GUI

稍微简化的代码如下所示:

  package require Tk
  set sv 1
  ttk::spinbox .sp -from 1 -to 9 -textvariable ::sv \
   -command {
     after 50                 ;# some processing imitated
     puts [incr ::tmp]:$::sv  ;# changes shown in CLI - ok
     update                   ;# changes shown in GUI - ???
   }
  pack .sp
问题是,当点击spinbox的箭头(更多的是“向上”而不是“向下”,但我没有发现任何规律性)并按下10-20秒时,spinbox进入无限更新循环,如
put
所示

当然,原因是
命令中的
update
,但是我不能没有它

在Windows(Tk 8.6.8)和Linux(Tk 8.6.10)、
ttk::spinbox
spinbox
中进行了尝试,所有这些都暴露了这种怪癖


有什么办法克服这个问题吗?非常感谢您的帮助。

通常,不要从
-command
回调中更新spinbox变量,尤其是不要从
-command
回调中运行
update
该命令允许处理事件(它运行一个辅助事件循环,直到事件队列耗尽)这正是你问题的根源。(我还建议不要执行
更新idletasks
;这将触发问题核心的重新配置和重画。)

相反,只需停止运行命令回调。它将控制权返回到Tk小部件,Tk小部件又将返回到主事件循环。我们还建议您不要在回调中进行大量处理,而是将此类处理安排在以后进行。具体如何做到这一点可能很复杂,而且肯定是特定于应用程序的。稍后移动处理的一种方法是将其放入在
事件之后运行的
过程中,如下所示:

package require Tk
set sv 1
proc updateVar {varName} {
    upvar "#0" $varName var
    after 50;  # Processing...
    incr var;  # Actually update the variable
}
ttk::spinbox .sp -from 1 -to 9 -textvariable ::sv \
    -command {after 0 updateVar ::sv}
pack .sp
请注意,这不会调用
update
。更大的代码延迟可能涉及线程或子进程。正如我所说的,要做到这一点可能很复杂。尤其是当鼠标按钮按下时对GUI布局的更改导致所选值发生更改,从而导致GUI布局发生更改时…

更新
包含在其
-命令
选项中时,我演示了spinbox的奇怪行为

存档中有两个测试:

test1.tcl提供了一种不应该这样做的方法。有两个问题:

  • -命令
    代码不会移动到单独的过程中
  • update
    立即从
    -命令触发
结果见test1 spx.mp4:当按下spinbox箭头10-20秒时,spinbox进入无限更新周期。这种行为是不规则的,尽管当焦点切换到另一个应用程序时会很好地显示出来

tcl提供了一种克服这种怪癖的方法。空闲后的
用于延迟更新。您也可以在0之后使用
进行此操作


在“真实测试”中,我对
-命令使用以下步骤:

proc fontszCheck {} {
  lappend ::afters [after 0 {
    foreach a $::afters {after cancel $a}
    set ::afters [list]
    ::t::toolBut 4 -3
  }]
}

希望这些信息在处理Tk spinbox时有用。

我不能重复这个问题。按照Donal在回答中的说明,将处理移到循环之外。将更新移动到处理过程中。这种类型的回访应该非常简短。谢谢你,多纳尔,谢谢你,布拉德,我非常感谢你的建议。知道
更新被认为是有害的
,我没有准备好我的问题,例如,重现问题(更详细,包括视频和所有内容)。我有罪。尽管如此,我还是会努力在这个问题上做得更好。