How to programmatically open a menu in python tkinter?

I have a graphical user interface with a menu. I would like to be able to open these menus programmatically, as if the user clicked on them.

My first guess was invoke, but it has no visible effect. I know that I can open the menu with tk_popup, but cannot determine the coordinates. The return value of the function ypositiondoes not look useful. Strange, I can't even get the width of the menu bar - it's always 1.

I know that I can bind a menu key to a key event with underlineand that I could create such an event programmatically, but I really would not want to do this.

import Tkinter as tk

class MenuBar(tk.Menu):
     def __init__(self, root):
         tk.Menu.__init__(self, root)
         self.root = root
         self.menu_file = tk.Menu(m, tearoff=False)
         self.menu_file.label = 'File'
         self.menu_file.add_command(label='save')
         self.menu_file.add_command(label='open')

         self.menu_edit = tk.Menu(m, tearoff=False)
         self.menu_edit.label = 'Edit'
         self.menu_edit.add_command(label='add')
         self.menu_edit.add_command(label='remove')

         self.menus = (
             self.menu_file,
             self.menu_edit,
         )
         for menu in self.menus:
             self.add_cascade(label=menu.label, menu=menu, underline=0)

     def invoke(self, menu):
         if menu in self.menus:
             index = self.index(menu.label)
         else:
             index = menu
         print("invoke({!r})".format(index))
         tk.Menu.invoke(self, index)

     def open_menu(self, menu):
         x = self.root.winfo_rootx()
         y = self.root.winfo_rooty()
         print("yposition: {}".format(self.yposition(self.index(menu.label))))
         print("mb.width : {}".format(self.winfo_width()))
         print("mb.geometry: {}".format(self.winfo_geometry()))
         print("tk_popup({x},{y})".format(x=x, y=y))
         menu.tk_popup(x,y)
         pass

m = tk.Tk()
mb = MenuBar(m)
m.config(menu=mb)
m.update()
m.bind('f', lambda e: mb.invoke(mb.menu_file))
m.bind('e', lambda e: mb.invoke(mb.menu_edit))
m.bind('<Control-f>', lambda e: mb.open_menu(mb.menu_file))
m.bind('<Control-e>', lambda e: mb.open_menu(mb.menu_edit))
m.mainloop()

Thanks in advance.

EDIT: , mb.menu_file.invoke(0). , tearoff True, , , . - ( - ), .

tearoff = True mb.invoke(mb.menu_file) - ( "invoke (1)" ).

postcascade, , , . - - . tcl documentation : " pathName , , ". , m.config(menu=mb) mb.update(); mb.post(m.winfo_rootx(), m.winfo_rooty()), . ( post tk_popup, .) , ; , , , .

, "" ? , effbot : " , , , , Tkinter." ( , post, , - tk_popup .) , , . , , , . . , ?

, : , . , , .

, , , . , , .

+4
1

invoke tearoff. tearoff, .

, , "postcascade". tkinter , (root.tk.eval(str(mb)+' postcascade 1'), , , .

, .

tk Menubutton <<Invoke>>. , , :

import Tkinter as tk
import ttk

def log(command):
    print 'running {} command'.format(command)

class MenuBar(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master, bd=1, relief=tk.RAISED)

        file_btn = tk.Menubutton(self, text='File')
        menu_file = tk.Menu(file_btn, tearoff=False)
        menu_file.add_command(label='save', command=lambda: log('save'))
        menu_file.add_command(label='open', command=lambda: log('open'))
        file_btn.config(menu=menu_file)
        file_btn.pack(side=tk.LEFT)
        master.bind('f', lambda e: file_btn.event_generate('<<Invoke>>'))

        edit_btn = tk.Menubutton(self, text='Edit')
        menu_edit = tk.Menu(edit_btn, tearoff=False)
        menu_edit.add_command(label='add', command=lambda: log('add'))
        menu_edit.add_command(label='remove', command=lambda: log('remove'))
        edit_btn.config(menu=menu_edit)
        edit_btn.pack(side=tk.LEFT)
        master.bind('e', lambda e: edit_btn.event_generate('<<Invoke>>'))

m = tk.Tk()
m.geometry('300x300')
mb = MenuBar(m)
mb.pack(side=tk.TOP, fill=tk.X)
m.mainloop()

, , .

+2

Source: https://habr.com/ru/post/1674604/


All Articles