代码之家  ›  专栏  ›  技术社区  ›  Nae

按下按钮时如何查看菜单?

  •  3
  • Nae  · 技术社区  · 7 年前

    跟进 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。

    2 回复  |  直到 7 年前
        1
  •  1
  •   CommonSense    7 年前

    琐事

    这个技巧在X窗口系统(读作Unix)中有效,因为“Alt键控”由 tk 自身通过 tk::TraverseToMenu 函数,它绑定到 all 在那种情况下绑定标签。

    在你的情况下 tk公司 检测,它在 Win 环境,并绑定 tk::遍历菜单 功能仅适用于 Menubutton bind标记,因为在这种情况下,“Alt键控”由本机处理 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::遍历菜单 工作正常-尝试将空字符串或任意字符作为 char 无法找到带wich菜单的参数。只有当你试图在窗户房子附近的草坪上玩耍时,问题才会出现。

    您在这种情况下的最佳选择: 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()
    
        2
  •  1
  •   Donal Fellows    7 年前

    Tkinter按钮不应该这样工作; 这就是菜单按钮的作用。 但是,如果要继续攻击按钮,则需要绑定到按钮上的事件,而不仅仅是使用命令回调(当按钮处于待命状态时,在按钮上方释放鼠标按钮1时会触发回调;当鼠标按钮1按下按钮上方时会发生待命)。

    我真的建议使用菜单按钮( tk.Menubutton )取而代之的是。它的设计目的是让用户更容易 就像按下时会显示菜单一样。