【问题标题】:How to view a menu when a button is pressed?按下按钮时如何查看菜单?
【发布时间】:2018-06-03 08:56:14
【问题描述】:

跟进this question,当按下按钮Test 时,我试图查看(与单击鼠标左键时相同)菜单sub1,但我不能。在以下代码中,按钮似乎改为冻结 GUI:

import tkinter as tk

root = tk.Tk()
menubar = tk.Menu(root)

sub1 = tk.Menu(menubar, tearoff=0)
sub1.add_command(label="Item 1", command=lambda : print("item 1"))
sub1.add_command(label="Item 2", command=lambda : print("item 2"))


menubar.add_cascade(menu=sub1, label="Sub1", underline=0)
root.config(menu=menubar)

def cb(*args):
    root.tk.call('::tk::TraverseToMenu', root, 'S')

tk.Button(root, text="Test", command=cb).pack()

root.mainloop()

我也尝试过update_idletasks() 无济于事。我该如何解决这个问题?

试过了:

Windows7、Python 3.6、Tkinter 8.6。

【问题讨论】:

  • 您的代码适用于我(python3、Debian)。您使用的是什么操作系统?
  • 你有seen this吗?

标签: python windows tkinter tcl tk


【解决方案1】:

琐事

这个技巧在 X Window 系统(读取为 Unix)中有效,因为“Alt-keying”由 tk 本身通过 tk::TraverseToMenu 函数处理,在这种情况下绑定到 all 绑定标签.

在您的情况下,tk 检测到它在Win 环境中工作,并将tk::TraverseToMenu 函数仅绑定到Menubutton 绑定标签,因为在这种情况下,“Alt-keying”由本机@处理987654333@wm。

menu.tcl中的源代码代表了所说的:

if {[tk windowingsystem] eq "x11"} {
    bind all <Alt-KeyPress> {
    tk::TraverseToMenu %W %A
    }

    bind all <F10> {
    tk::FirstMenu %W
    }
} else {
    bind Menubutton <Alt-KeyPress> {
    tk::TraverseToMenu %W %A
    }

    bind Menubutton <F10> {
    tk::FirstMenu %W
    }
}

解决方案

当您按下 Alt 键时,Windows sends a message,表示 the Alt-key is pressed down,并等待 for another message,其中包含指定字符作为 ANSI 代码。 接收到指定字符后,wm 正在尝试查找要打开的菜单。

同时tk::TraverseToMenu 运行良好 - 尝试将空字符串或任意字符作为char 参数传递,但找不到该菜单。仅当您尝试在 Windows 房屋附近的草坪上玩耍时才会出现此问题。

在这种情况下你最好的选择:SendMessagekeybd_event

所以一个完整的黑客(正如@Donal Fellows 所说)是这样的:

import tkinter as tk

root = tk.Tk()

if root._windowingsystem == 'win32':
    import ctypes

    keybd_event = ctypes.windll.user32.keybd_event
    alt_key = 0x12
    key_up = 0x0002

    def traverse_to_menu(key=''):
        if key:
            ansi_key = ord(key.upper())
            #   press alt + key
            keybd_event(alt_key, 0, 0, 0)
            keybd_event(ansi_key, 0, 0, 0)

            #   release alt + key
            keybd_event(ansi_key, 0, key_up, 0)
            keybd_event(alt_key, 0, key_up, 0)

else:
    #   root._windowingsystem == 'x11'
    def traverse_to_menu(key=''):
        root.tk.call('tk::TraverseToMenu', root, key)

menubar = tk.Menu(root)

sub1 = tk.Menu(menubar, tearoff=0)
sub1.add_command(label='Item 1', command=lambda: print('item 1'))
sub1.add_command(label='Item 2', command=lambda: print('item 2'))

menubar.add_cascade(menu=sub1, label='Sub1', underline=0)
root.config(menu=menubar)

traverse_button = tk.Button(root, text='Test', command=lambda: traverse_to_menu('S'))
traverse_button.pack()

root.mainloop()

【讨论】:

  • 非常好,非常感谢您的回答!我不明白的一件事是为什么你定义函数而不是 if/else 而不是用 if/else 定义函数?
  • @Nae 将依赖于操作系统的东西(如导入)分开是一个品味问题和我的习惯。真正的问题是为什么像 这样的 tkinter 生成的事件没有效果,而 的行为与预期一样。
【解决方案2】:

Tkinter 按钮不应该那样工作; 这就是菜单按钮的用途。但是如果您要继续破解按钮,则需要绑定到按钮上的事件,而不仅仅是使用命令回调(已触发on mouse-button-1 在按钮被武装时释放按钮;当 mouse-button-1 被按下按钮时发生武装)。

我真的建议改用菜单按钮 (tk.Menubutton)。这对用户来说更容易,因为它的设计看起来就像按下时会发布一个菜单。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 1970-01-01
    相关资源
    最近更新 更多