0

I am making a menubar in tkinter in one of the menu in the menu bar, I have some check_button and when one of these check_button is clicked, the menu closes, but I want to keep this menu open. I want to know if there is a simple way of doing it. I am making a map editor and in my menu I choose to show or not map's elements.

menubar = tk.Menu()
viewMenu = tk.Menu(menubar, tearoff = 0)
viewMenu.add_check_button(label = "Obstacles", varibale = test1)
viewMenu.add_check_button(label = "Ground", varibale = test2)
menubar.add_cascade(menu = viewMenu, label = "View")
win.config(menu = menubar) # win = tk.Tk()
icetom 54
  • 63
  • 7
  • 1
    Could you include a code snippet that creates the menu so that we can see what you have so far? This way people who want to help you won't have to start from scratch. – j_4321 Dec 19 '17 at 21:09
  • 2
    Please include a [mcve] in your questions. – Novel Dec 19 '17 at 21:12
  • btw: menu has option `tearoff` so you can tear off menu (cut off from menubar) and it can stay as popup menu. Atleast it works on Linux. – furas Dec 19 '17 at 21:17
  • @furas thx it's working but not very pretty :/ – icetom 54 Dec 19 '17 at 21:25
  • maybe it is not very pretty but it's working ;) I susspect to keep menu open would need many, many works - or maybe you would need to write all menu from scratch. But I can be wrong. – furas Dec 19 '17 at 23:01
  • The code above does not work for me so I can't help even though I want to. – Nae Dec 20 '17 at 08:53

2 Answers2

0

Below example opens View back each time a checkbutton is selected:

import tkinter as tk

root = tk.Tk()

test1, test2 = tk.BooleanVar(), tk.BooleanVar()

def cb():
    print(test1.get(), test2.get())
    root.tk.call('::tk::TraverseToMenu', root, 'v')

menubar = tk.Menu(root)
viewMenu = tk.Menu(menubar, tearoff = 0)
viewMenu.add_checkbutton(label = "Obstacles", variable = test1, command=cb)
viewMenu.add_checkbutton(label = "Ground", variable = test2, command=cb)
menubar.add_cascade(menu = viewMenu, label = "View")
root.config(menu = menubar) # win = tk.Tk()

root.mainloop()

See more info here and here.


Based on the answer that accounts for windows' special case here a very similar code can be written as follows:

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)

test1, test2 = tk.BooleanVar(), tk.BooleanVar()
menubar = tk.Menu(root)
viewMenu = tk.Menu(menubar, tearoff = 0)
viewMenu.add_checkbutton(label = "Obstacles", variable = test1,
                            command=lambda : traverse_to_menu('v'))
viewMenu.add_checkbutton(label = "Ground", variable = test2,
                            command=lambda : traverse_to_menu('v'))
menubar.add_cascade(menu = viewMenu, label = "View")
root.config(menu = menubar) # win = tk.Tk()

root.mainloop()

key variable to the traverse_to_menu is 'v' as Alt - V opens the menu via keyboard. As in key needs to be the non-modifying key that by default opens the menu using keyboard.

Nae
  • 14,209
  • 7
  • 52
  • 79
  • 1
    I just ran this under Py3, and I don't see the viewMenu reappearing after one of the checkbuttons has been clicked... Is something missing? I, too, am on Windows (10). From what I've seen at the two links you reference, people running Linux seem to have better luck with this. I did try setting tearoff=1, but that had no effect. – GaryMBloom Dec 20 '17 at 20:41
  • @Gary02127 Thanks to [CommonSense](https://stackoverflow.com/users/6634373/commonsense)'s [answer](https://stackoverflow.com/a/47927605/7032856) I was able to easily modify their code to provide the answer here. – Nae Dec 21 '17 at 16:04
0

In my case, I did as follows:

first creating primary things as

window=Tk()
mb = Menubutton (window, text="Test", relief=RAISED)
var = BooleanVar()

Then adding some checkbutton as below:

mb.menu.add_checkbutton(label='Test btn', variable=var,command = lambda: menu_click("some input"))
#adding some other checkbuttons

Finally creating menu_click function:

def menu_click(input):
   if input == "some input":
      mb.menu.post(mb.winfo_rootx(), mb.winfo_rooty())

In which mb.winfo_rootx(), mb.winfo_rooty() are x and y coordinates of desired opennig location.

s.abbaasi
  • 952
  • 6
  • 14