tk / tcl的几何管理器的奇怪行为

时间:2013-06-16 15:09:36

标签: tcl tk

我想设置窗口的宽度,为此我使用代码:

wm geometry .sigsetting_menu [regsub {\d+x} [wm geometry .sigsetting_menu] {463x}]

将其设置为463像素宽。但是当我只运行这一行时,窗口的高度设置为1.如果我在该行之前运行带有任何参数的命令puts,甚至是没有换行的空字符串,它什么都不做:

puts -nonewline ""

然后我得到了正确的结果,即窗口的高度不是1.导致它的原因是什么,我该如何解决这个问题?


关于正确编码标准的评论:

我知道我在这里使用magic number,这是一个非常糟糕的做法。这是我所遇到的问题的临时解决方案,将来“魔数”将被替换为根据窗口与帧中其他窗口的关系计算的值,但代码将是相同的只有463将替换为$width

2 个答案:

答案 0 :(得分:4)

Tk推迟窗口创建,几何计算(在设置窗口内容时可能相当复杂且大多数没有意义)和实际绘制内容直到应用程序空闲,直到它处于事件循环中并且没有待处理的待处理实际事件。 (在这种意义上,定时器事件在它们触发之前不会等待。)这通常是正确的做法:它使得几乎所有普通代码的Tk看起来都非常快。所有这些处理都是使用一个名为“空闲事件”的概念来处理的,Tk在内部使用了大量内容,您可以通过after idle创建自己的事件。

然而,前一段的结果是你不能直接做你想做的事;当你询问有关窗口几何的当前信息时,它还没有被计算出来,所以你会得到一些(不相关的)默认值。您可以强制刷新挂起的空闲处理(使用update idletasks,通常缩写为update idle),但这可能会导致一些棘手的重入问题,并且还会触发显示器难看的闪烁(因为映射和绘图,你也不能阻止)。正因为如此,你实际应该做的是推迟几何调整,直到他们自己的空闲事件,如下所示:

after idle {
    wm geometry .sigsetting_menu [regsub {\d+x} [wm geometry .sigsetting_menu] "463x"]
}

如果您要做很​​多这类事情,请使用帮助程序来保持代码简单,list生成回调(它完全正确引用)。

proc setGeometryWidth {window width} {
    wm geometry $window [regsub {\d+x} [wm geometry $window] "${width}x"]
}
after idle [list setGeometryWidth .sigsetting_menu 463]

另外,您确定将宽度设置为明确的像素数是明智的吗?高分辨率显示器即将推出......

答案 1 :(得分:1)

由于您没有显示您正在创建该窗口的位置,因此我猜测您在创建该窗口后的时间不长,例如:

toplevel .sigsetting_menu
wm geometry .sigsetting_menu [regsub {\d+x} [wm geometry .sigsetting_menu] {463x}]

问题在于创建窗口需要时间,而且它分阶段发生(我不是这方面的专家所以我确定确切的过程),首先它创建窗口然后才调整它,但是TCL工作“太快”,因此它在调整原始窗口大小之前调用第二行,因此高度保持1px但宽度会改变。但是当你调用类似puts的东西需要花费时间时,它会设法正确调整窗口的大小。 正确的方法是调用update这种情况的特殊命令,它停止当前代码的执行,直到事件循环为空。 所以你应该这样做:

toplevel .sigsetting_menu
update idle
wm geometry .sigsetting_menu [regsub {\d+x} [wm geometry .sigsetting_menu] {463x}]