跟进this question,我试图查看(与用鼠标左键单击时相同)菜单,sub1
,按下按钮,Test
,但我不能。在下面的代码按钮似乎冻结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。
这个技巧在X Window系统中工作(读作Unix),因为“Alt-keying”由tk
本身通过tk::TraverseToMenu
函数处理,在这种情况下绑定到all
bind-tag。
在你的情况下,tk
检测到它在Win
环境中工作,并且仅将tk::TraverseToMenu
函数绑定到Menubutton
绑定标记,因为在这种情况下,“Alt-keying”由本地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 sends a message,它发出the Alt-key is pressed down信号,并等待包含指定字符作为ANSI代码的for another message。收到指定的字符后,wm正在尝试查找要打开的菜单。
同时tk::TraverseToMenu
效果很好 - 尝试传递空字符串或任意字符作为char
参数,无法找到菜单。问题只发生在你试图在Windows房子附近的草坪上玩耍时。
在这种情况下你最好的赌注:SendMessage或keybd_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()
Tkinter按钮不应该以这种方式工作;这就是menubutton的用途。但是如果你要继续攻击一个按钮,你将需要绑定到按钮上的事件,而不仅仅是使用命令回调(当按钮是按钮时,按钮上的鼠标按钮1释放时会触发该回调。当按下鼠标按钮-1时,会发生布防;
我真的建议使用menubutton(tk.Menubutton
)代替。它对用户来说更容易,因为它被设计成看起来像是在按下时发布菜单。