Tcl 当toplevel尚未';这不是焦点
我的顶层有一个Tcl 当toplevel尚未';这不是焦点,tcl,tk,Tcl,Tk,我的顶层有一个ttk::progressbar(唯一的),我通过以下功能更新它: proc progress {x} { global prog set prog [expr fmod(($prog +$x),100)] update idletasks } prog是通过-variable选项绑定到progressbar的变量 如果我把注意力集中在窗户上,一切都会好起来的。如果切换到另一个窗口,progressbar将停止更新,即使切换回应用程序,它也不会重新启动 我在Windo
ttk::progressbar
(唯一的
),我通过以下功能更新它:
proc progress {x} {
global prog
set prog [expr fmod(($prog +$x),100)]
update idletasks
}
prog
是通过-variable
选项绑定到progressbar的变量
如果我把注意力集中在窗户上,一切都会好起来的。如果切换到另一个窗口,progressbar将停止更新,即使切换回应用程序,它也不会重新启动
我在Windows7上使用tcl/tk 8.6(以防万一)
这种行为的原因可能是什么?我是否错过了有关如何更新进度条的内容
编辑
似乎一个完整的
更新
会起作用,所以问题是为什么会出现这种情况,以及是否有任何方法可以避免完全更新刷新。当您更新进度条小部件的值(或者,通常,任何小部件的值或配置)时,Tk会创建一个内部空闲*事件来进行重绘;其思想是,如果您更新一行中的多个内容以响应一系列事件(这是一件非常常见的事情!),那么您只会得到一个小部件的重画。这在大多数情况下都能很好地工作,但当你在做一些繁忙的动画循环时就不行了。
执行更新idletasks
可立即发生任何计划的空闲事件;此时将处理内部生成的重画
但这还不是全部。还有通过真实事件从外部世界(即主机窗口系统)生成的外部重画:在Windows上,WM_PAINT
,在X11上,Expose
,在OSX上,…,这在OSX上很复杂。(为了论证而忽略该平台。)因为这些外部事件来自外部世界,它们只会被完整的事件循环注意到-低级事件处理系统在收到它们之前不知道它们被请求重画-这意味着使用主事件循环,或由vwait
启动的附属系统,完整的更新
,或tkwait
。(事实上,处理这些外部重画事件的方式是在空闲事件中安排重画,因为可能还有其他事件,如小部件大小调整或焦点更改,也需要同时处理,并且也需要重画。)
建议的处理方法是将正在执行长时间运行的处理的代码拆分,以便可以定期返回事件循环,并允许它处理任何挂起的外部事件。在8.5及之前的版本中,您可以不时在$afewmillseconds doTheNextBit之后使用;这需要对代码进行结构化,使其以延续传递样式工作,这可能有点痛苦。另一方面,在8.6中,您可以将长时间运行的代码放入一个协同程序中,并在$afewmillseconds[info corroutine]之后使用停止一点;在不显著中断代码流的情况下产生
不太推荐的做法是加入更新
。问题是它会启动一个辅助事件循环,如果您尝试重新进入任何长时间运行的处理,这可能会导致堆栈耗尽问题。通过适当的互锁(例如,禁用可能会在长时间处理过程中导致问题的按钮)可以实现这一点,但这确实更加棘手。您还可以考虑将处理从一个单独的非GUI线程**,只需将消息发送回主GUI线程,以使进度条发生变化。(顺便说一句,Tcl将线程间消息视为事件)在您的情况下,使用多线程可能有意义,也可能没有意义
*您可以在空闲后使用创建自己的空闲事件,但通常不需要它们。
**真正的多线程GUI非常疯狂,而Tk无论如何也不能以这种方式工作。带有Tk的每个线程都有自己的完整副本。您在哪个平台上运行?Win 7。我会更新这个问题。谢谢,多纳尔。非常全面,我喜欢Tcl/Tk的公寓模式。在Java中,没有任何东西阻止您访问其他线程中的某些GUI内容,这可能会导致错误/未定义的行为。很多刚接触Java的人都犯了这个错误(我也犯过一次)。