【问题标题】:<<MenuSelect>> in Tcl/Tk 8.6.11 and onTcl/Tk 8.6.11 及更高版本中的 <<MenuSelect>>
【发布时间】:2022-01-08 18:08:08
【问题描述】:

我在 Tcl/Tk 8.6.11 中遇到了 MenuSelect 事件的问题(在 Linux、Debian 10.7 中尝试过)。

事实上,它根本不会触发主菜单和可撕下的菜单。虽然在 Tcl/Tk 8.6.9 甚至在 8.6.11 中都可以正常工作 - 只是在菜单没有被撕掉时。

测试代码:

package require Tk
proc ::somehandler {w wt} {
  puts "Step [incr ::step]: $w / $wt, index=[$wt index active]"
}
set w [menu .m -tearoff 1]
$w add command -label {Item 1}
$w add command -label {Item 2}
bind $w <<MenuSelect>> [list ::somehandler $w %W]
pack [button .b -text "Click me" \
  -command {tk_popup .m [winfo pointerx .] [winfo pointery .]}]

我尝试了以下(虽然很愚蠢)替换:

event delete <<MenuSelect>>
event add <<MenuSelect>> <Motion>
bind $w <<MenuSelect>> [list ::somehandler $w %W]

...结果相同。

看起来,它与 Tk 中处理的菜单路径有关,有点棘手,如上例所示。

我懒得在从 8.6.9 切换到 8.6.11/12、8.7 等时更改标准代码。

TIA 的任何提示。

【问题讨论】:

    标签: menu tcl tk tcltk


    【解决方案1】:

    这可能与菜单使用克隆进行撕裂和菜单栏的事实有关。来自documentation

    当菜单设置为顶层窗口的菜单栏时,或者当菜单 被撕下,菜单的克隆被制作。这个克隆是一个菜单小部件 就其本身而言,但它是原始的孩子。的变化 原来的配置都反映在克隆中。此外, 指向的任何级联也被克隆,以便菜单遍历 会正常工作。当撕下或 菜单栏消失,或者原始菜单被破坏时。

    我不记得克隆到底是怎么命名的,但你通常不会直接与它们互动;只有通过事件处理才能真正看到它们。 (我只在为菜单做工具提示时才需要处理它们。)

    通常,最好避免使用&lt;&lt;MenuSelect&gt;&gt;,而只需在可以选择的条目上设置-command(或者只为checkbuttonradiobutton 条目设置正确的模型变量)。并完全避免撕裂;它们是 25 年前过时的菜单交互方式。

    【讨论】:

    • 那是 8.7 文档,但菜单在功能上已经很长一段时间了;我们几乎没有理由改变它们。 (克隆之所以存在,是因为菜单可以是撕下的、菜单栏和菜单按钮的直接弹出窗口,所有这些都同时可见。您可能不想这样做,但这是可能的。)
    • 您好,Donal,谢谢您的回答,我希望得到它。虽然,唉,它并不令人满意。我不需要菜单项上的命令,而是观察它们的选择。这一切都是为了为他们显示工具提示。我有一个 Csaba 的建议如何解决这个问题,在尝试之后我会在这里发布它作为答案,只为那些也需要它的人。尽管如此,我仍然希望这个问题的主要解决方案,因为它是 8.6.11 中引入 Tk 的一个真正的错误。
    【解决方案2】:

    对于 Tk 8.6.11+,应使用 bind Menu 而不是 bind $w(用于单个菜单项)。它为事件处理程序添加了一些技巧,该处理程序应该计算要处理的菜单项。

    即我们有类似的东西:

    bind Menu <<MenuSelect>> [list ::somehandler %W]
    

    如果菜单项在克隆菜单中,则 %W 通配符作为“克隆”名称传递给 ::somehandler

    并且 ::somehandler 应该计算出谁是现实中的 %W。

    Csaba Nemethi 建议使用类似 clonename 的过程(来自 BWidget 包的 utils.tcl)。此过程从“普通”菜单项的路径中获取克隆名称。

    这里是它的一些修改版本:

    proc clonename {mnu} {
      # Gets a clone name of a menu.
      #   mnu - the menu's path
      # This procedure is borrowed from BWidget's utils.tcl.
    
      set path [set menupath {}]
      set found 0
      foreach widget [lrange [split $mnu .] 1 end] {
        if {$found || [winfo class "$path.$widget"] eq {Menu}} {
          set found 1
          append menupath # $widget
          append path . $menupath
        } else {
          append menupath # $widget
          append path . $widget
        }
      }
      return $path
    }
    

    作为使用示例,见test.tcl的:

    http://chiselapp.com/user/aplsimple/repository/baltip/zip/trunk/baltip.zip

    感谢 Donal 和 Csaba 的提示。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-24
      • 1970-01-01
      • 2017-05-03
      • 1970-01-01
      • 2021-05-20
      • 1970-01-01
      • 2020-07-18
      • 2018-02-18
      相关资源
      最近更新 更多