Using column breaks and sub-menus, makes navigation with the mouse almost impossible. e.g. with the code below
* open the menu * hover the mouse over "one" * hover the mouse over "Item #40" * <Left-mouse-click> to select the submenu * ... try to select in the new submenu "Item #40 : 2" with the mouse I cannot, since when I hover the mouse over the other items their respective submenu opens. I can only selected it with the keyboard. import tkinter as tk #------------------------------------------------------------------------------- def show_menu(event): global root menu = tk.Menu(root) for label in ["one","two","three","four"]: submenu = tk.Menu(menu) menu.add_cascade(label=label, menu=submenu) for i in range(101): sub2menu = tk.Menu(submenu) sublabel = f"Item #{i}" submenu.add_cascade(label=sublabel,menu=sub2menu) if i and i%20==0: submenu.entryconfigure(i, columnbreak=1) for j in range(10): sub2menu.add_command(label=f"{sublabel} : {j}") menu.tk_popup(event.x_root, event.y_root) #------------------------------------------------------------------------------- if __name__ == "__main__": root = tk.Tk() tk.Label(root, text="<1> Left click to show menu").pack() tk.Label(root, text="<q> to exit").pack() root.bind("<1>", lambda e: show_menu(e)) root.bind("<3>", lambda e: show_menu(e)) root.bind("<space>", lambda e: show_menu(e)) root.bind("<Key-q>", lambda e: root.destroy()) root.mainloop() ________________________________ From: Vasilis Vlachoudis <vasilis.vlachou...@cern.ch> Sent: Monday 18 September 2023 09:42 To: Michael Lange <klappn...@web.de> Cc: tkinter-discuss@python.org <tkinter-discuss@python.org> Subject: Re: [Tkinter-discuss] Navigation in menu with multiple columns Great, many thanks Michael! ________________________________ From: Michael Lange <klappn...@web.de> Sent: Sunday 17 September 2023 02:14 To: Vasilis Vlachoudis <vasilis.vlachou...@cern.ch> Cc: tkinter-discuss@python.org <tkinter-discuss@python.org> Subject: Re: [Tkinter-discuss] Navigation in menu with multiple columns Hi Vasilis, On Fri, 15 Sep 2023 09:55:49 +0000 Vasilis Vlachoudis <vasilis.vlachou...@cern.ch> wrote: > Hi Michael, > > here is a snipped of a code and what I've managed up to now thanks, I get your point now :-) I toyed around with your example a bit and came up with a custom menu class (see below; for testing I added a few useless separators and another submenu to the demo code). It's far from being perfect, but at least the keyboard navigation appears to work (It might require more thorough testing, though. Separators appear to be especially tricky.). Just for the fun of it I also added keybindings for the PageUp, PageDown, Home and End keys, which I thought might come in handy when dealing with huge submenus. Have a nice day, Michael ################################################################ import tkinter class GriddedMenu(tkinter.Menu): '''Menu with lots of menu items arranged in a grid.''' # TODO: insert(), delete(), add_cascade(), add_checkbutton(), # add_radiobutton(), add_separator(), configure() def __init__(self, parent, numrows=20, **kw): tkinter.Menu.__init__(self, parent, **kw) self.numrows = numrows self._curindex = -1 if self.type(0) == 'tearoff': self._curindex = 0 self.bind("<Right>", self._on_key_right) self.bind("<Left>", self._on_key_left) self.bind("<Prior>", self._on_key_pageup) self.bind("<Next>", self._on_key_pagedown) self.bind("<Home>", self._on_key_home) self.bind("<End>", self._on_key_end) def add_cascade(self, **kw): # FIXME: handle columnbreaks tkinter.Menu.add_cascade(self, **kw) self._curindex += 1 def add_command(self, **kw): tkinter.Menu.add_command(self, **kw) self._curindex += 1 if (self._curindex >= self.numrows) and \ (self._curindex % self.numrows == 0): self.entryconfigure(self._curindex, columnbreak=1) def add_separator(self, **kw): # FIXME: handle columnbreaks tkinter.Menu.add_separator(self, **kw) self._curindex += 1 def _on_key_left(self, event): index = self.index('active') if index - self.numrows >= 0: newindex = index - self.numrows while (newindex >= 0) and (self.type(newindex) == 'separator'): newindex -= self.numrows if newindex >= 0: self.activate(newindex) return 'break' def _on_key_right(self, event): index = self.index('active') end = self.index('end') if index + self.numrows <= end: newindex = index + self.numrows while (newindex <= end) and (self.type(newindex) == 'separator'): newindex += self.numrows if newindex <= end: self.activate(newindex) return 'break' def _on_key_pageup(self, event): index = self.index('active') row = index % self.numrows newindex = index - row while self.type(newindex) == 'separator': newindex += 1 self.activate(newindex) def _on_key_pagedown(self, event): index = self.index('active') row = index % self.numrows newindex = min(self.index('end'), index + (self.numrows - row - 1)) while self.type(newindex) == 'separator': newindex -= 1 self.activate(newindex) def _on_key_home(self, event): newindex = 0 while self.type(newindex) == 'separator': newindex += 1 self.activate(newindex) def _on_key_end(self, event): newindex = self.index('end') while self.type(newindex) == 'separator': newindex -= 1 self.activate(newindex) #------------------------------------------------------------------------------ if __name__ == "__main__": def show_menu(event): menu = tkinter.Menu(tearoff=0) for label in ["one","two","three","four"]: submenu = GriddedMenu(menu) menu.add_cascade(label=label, menu=submenu) for i in range(8): submenu.add_command(label=f"Item #{i}") submenu.add_separator() for i in range(8, 57): submenu.add_command(label=f"Item #{i}") submenu.add_separator() for i in range(57, 72): submenu.add_command(label=f"Item #{i}") submenu.add_separator() for i in range(72, 101): submenu.add_command(label=f"Item #{i}") submenu.add_separator() subsubmenu = tkinter.Menu(submenu) submenu.add_cascade(label='foo', menu=subsubmenu) subsubmenu.add_command(label='bar') submenu.add_separator() menu.tk_popup(event.x_root, event.y_root) root = tkinter.Tk() tkinter.Label(root, text="<1> Left click to show menu").pack() tkinter.Label(root, text="<q> to exit").pack() root.bind("<1>", show_menu) root.bind("<Key-q>", lambda e: root.destroy()) root.mainloop() ###############################################################################
_______________________________________________ Tkinter-discuss mailing list Tkinter-discuss@python.org https://mail.python.org/mailman/listinfo/tkinter-discuss