小知识
这个技巧在 X Window System(也称为 Unix)中适用,因为“Alt+键”由 tk::TraverseToMenu
函数处理,而该函数绑定在 all
bind-tag 上。
而在您的情况下,tk
检测到它在 Win
环境下运行,并将 tk::TraverseToMenu
函数仅绑定到 Menubutton
bind-tag 上,因为在这种情况下,“Alt+键”由本机的 Win
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会发送一条消息,其中包含Alt键已被按下的信号,并等待另一条消息,其中包含指定字符的ANSI代码。
收到指定字符后,wm会尝试找到要打开的菜单。
同时,tk::TraverseToMenu
运行良好 - 尝试将空字符串或任意字符作为char
参数传递,无法找到菜单。只有当您尝试在Windows房子附近玩耍时才会出现问题。
在这种情况下,您最好的选择是:
SendMessage或
keybd_event。
所以一个完整的hack(如@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())
keybd_event(alt_key, 0, 0, 0)
keybd_event(ansi_key, 0, 0, 0)
keybd_event(ansi_key, 0, key_up, 0)
keybd_event(alt_key, 0, key_up, 0)
else:
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()