在Tcl/Tk中抓住一个新窗口
我有一个GUI,其中有一个在新窗口中打开的属性窗口。在某些情况下,(随机且不可确定地再现),当我打开窗口时,会出现衰减误差:在Tcl/Tk中抓住一个新窗口,tcl,tk,Tcl,Tk,我有一个GUI,其中有一个在新窗口中打开的属性窗口。在某些情况下,(随机且不可确定地再现),当我打开窗口时,会出现衰减误差: grab failed: window not viewable 它不会干扰程序的正常功能,除了打印该消息之外,似乎对任何事情都没有任何影响 创建新窗口的代码为: proc _prop_menu_make_top {{elem {}}} { toplevel .prop_menu #...initialize some variables...
grab failed: window not viewable
它不会干扰程序的正常功能,除了打印该消息之外,似乎对任何事情都没有任何影响
创建新窗口的代码为:
proc _prop_menu_make_top {{elem {}}} {
toplevel .prop_menu
#...initialize some variables...
wm title .prop_menu "Properties for $_prop_attr(name)"
#...create and display the window widgets...
bind .prop_menu <Key-KP_Enter> {_prop_menu_ok_button}
bind .prop_menu <Return> {_prop_menu_ok_button}
bind .prop_menu <Escape> {_prop_menu_cancel_button}
# catch presses on the window's `x` button
wm protocol .prop_menu WM_DELETE_WINDOW {
_prop_menu_cancel_button
}
# make the top window unusable
center_the_toplevel .prop_menu
focus .prop_menu.main_frame.model_name.entry
grab release .
grab set .prop_menu
}
proc center_the_toplevel { window } {
if { [string equal $window [winfo toplevel $window]] } {
set width [winfo reqwidth $window]
set height [winfo reqheight $window]
set x [expr {([winfo vrootwidth $window] - $width) / 2}]
set y [expr {([winfo vrootheight $window] - $height) / 2 }]
wm geometry $window +${x}+${y}
}
return
}
proc _prop_menu_ok_button {} {
#....saving the needed data...
_prop_menu_cancel_button
}
proc _prop_menu_cancel_button {} {
destroy .prop_menu
# make the top window usable again
grab set .
# redraw the canvas
nlv_draw
}
proc_prop_menu_make_top{{{elem{}}{
toplevel.prop_菜单
#…初始化一些变量。。。
wm title.prop_菜单“属性为$prop_attr(名称)”
#…创建并显示窗口小部件。。。
bind.prop_菜单{{u prop_菜单{u ok_按钮}
bind.prop_菜单{{u prop_菜单{u ok_按钮}
bind.prop_菜单{{{u prop_菜单{u取消}
#catch按下窗口的“x”按钮
wm协议。属性菜单wm\U删除窗口{
_道具菜单取消按钮
}
#使顶部窗口无法使用
将顶层的属性菜单居中
focus.prop\u menu.main\u frame.model\u name.entry
抓住释放装置。
抓斗设置。道具菜单
}
进程中心{u顶层{window}{
如果{[string equal$window[winfo topflevel$window]]}{
设置宽度[winfo reqwidth$窗口]
设置高度[winfo reqheight$窗口]
集合x[expr{([winfo vrootwidth$window]-$width)/2}]
设置y[expr{([winfo vrootheight$window]-$height)/2}]
wm几何体$window+${x}+${y}
}
回来
}
程序属性菜单确定按钮{}{
#…保存所需的数据。。。
_道具菜单取消按钮
}
程序属性菜单取消按钮{}{
破坏。道具菜单
#使顶部窗口再次可用
抓取集合。
#重新绘制画布
nlv_绘图
}
有人知道是什么导致了这个问题吗?
有人对如何使bug更容易被重新复制有什么建议吗
编辑:
运行64位的Tcl 8.4.6版,不知道是哪个tk版本。解释
出于各种原因(一些技术、一些设计原则),Tk只允许在映射到屏幕上的窗口上设置抓取。这几乎肯定是你想要的;鼠标点击应该会进入一个你能看到的窗口
你遇到的问题是,你试图抢得太早了。特别是,Tk推迟为每个小部件创建底层X11/OS窗口(取决于平台),直到它完成决定该小部件的配置,当Tk变为“空闲”时,该配置将被视为。空闲被定义为当进入事件循环且没有待处理的事件时。此时,Tk告诉基本系统图形引擎分配屏幕属性(窗口)的矩形块并将其放在屏幕上。这反过来会触发一系列事件和处理(在这一点上有很多事情在进行),最终会向您显示窗口;只有当窗口显示时,您才能在其上设置抓取
那你怎么知道什么时候可以抓取?嗯,你得等窗户打开。这意味着等待一个事件:您可能会关心此任务的关键事件是
、
和
。它们分别指示窗口在逻辑上何时存在于根窗口中,何时实际可查看的内容发生更改,以及何时需要重新绘制某些内容。(在Windows上,第一个和最后一个都是等价的,Tk会在内部重新映射,但Windows根本不会告诉您实际的可见性变化
解决方案
等待小部件可抓取(然后进行抓取)的最简单方法是使用:
tkwait visibility $theWidget
grab set $theWidget
它只是在事件循环中等待
事件在该窗口中出现。(由于该平台上没有事件类型,因此无法在Windows上运行。)您可以将上述内容重写为:
bind $theWidget <Visibility> [list set waiting($theWidget) gotit]
vwait waiting($theWidget)
bind $theWidget <Visibility> {} ;# remove the binding again!
grab set $theWidget
但是,如果你做的不仅仅是设置抓斗,它可能会变得非常复杂。(Tcl 8.6的协同程序有助于解决这一混乱局面,但它们绝对不能移植到8.4。)
[*]我忘记了在使用非X11 Tk构建的OSX时是否存在问题。如果您在意,请自己检查。解释 出于各种原因(一些技术、一些设计原则),Tk只允许在映射到屏幕上的窗口上设置抓取。这几乎肯定是你想要的;鼠标点击应该会进入一个你能看到的窗口 你遇到的问题是,你试图抢得太早了。特别是,Tk推迟为每个小部件创建底层X11/OS窗口(取决于平台),直到它完成决定该小部件的配置,当Tk变为“空闲”时,该配置将被视为。空闲被定义为当进入事件循环且没有待处理的事件时。此时,Tk告诉基本系统图形引擎分配屏幕属性(窗口)的矩形块并将其放在屏幕上。这反过来会触发一系列事件和处理(在这一点上有很多事情在进行),最终会向您显示窗口;只有当窗口显示时,您才能在其上设置抓取 那你怎么知道什么时候可以抓取?嗯,你得等窗户打开。这意味着等待一个事件:您可能会关心此任务的关键事件是
、
和
。它们分别指示窗口在逻辑上何时存在于根窗口中,何时实际可查看的内容发生更改,以及何时需要重新绘制某些内容。(在Windows上,第一个和最后一个都是等价的,Tk会在内部重新映射,但Windows根本不会告诉您实际的可见性变化
解决方案
等待小部件变得可抓取(然后执行抓取)的最简单方法
bind $theWidget <Map> [list set waiting($theWidget) gotit]
vwait waiting($theWidget)
bind $theWidget <Map> {} ;# remove the binding again!
grab set $theWidget
bind $theWidget <Map> {
bind %W <Map> {}
grab set %W
}