Long Tkinter Menu

Eric Brunel eric_brunel at despammed.com
Thu Oct 5 04:01:13 EDT 2006


On Thu, 05 Oct 2006 02:33:54 +0200, Dustan <DustanGroups at gmail.com> wrote:

> I don't know if this is because of Tkinter (ie Tk) itself or the
> Windows default way of handling things, but when I create a very long
> menu (my test is shown below), the way it displays is rather sucky; the
> menu stretches from the top of the moniter's window to the bottom (no
> matter the size of the actual application).
>
> Is there any alternative format for how a long menu gets displayed? It
> would be nice if say, I could make the menu only go to the borders of
> the application itself (in this case, not that long).

To limit the menu in the application window, will be difficult. But here  
are two ways of automatically limiting the number of entries that can  
appear in a menu by specializing the Tkinter Menu class:

------------------------------------------------------
 from Tkinter import *

class LongMenu(Menu):
   """
   Automatically creates a cascade entry labelled 'More...' when the
   number of entries is above MAX_ENTRIES.
   """

   MAX_ENTRIES = 20

   def __init__(self, *args, **options):
     Menu.__init__(self, *args, **options)
     self.nextMenu = None

   def add(self, itemType, cnf={}, **kw):
     if self.nextMenu is not None:
       return self.nextMenu.add(itemType, cnf, **kw)
     nbEntries = self.index(END)
     if nbEntries < LongMenu.MAX_ENTRIES:
       return Menu.add(self, itemType, cnf, **kw)
     self.nextMenu = LongMenu(self)
     Menu.add(self, 'cascade', label='More...', menu=self.nextMenu)
     return self.nextMenu.add(itemType, cnf, **kw)


class AutoBreakMenu(Menu):
   """
   Automatically adds the 'columnbreak' option on menu entries to make
   sure that the menu won't get too high.
   """

   MAX_ENTRIES = 20

   def add(self, itemType, cnf={}, **kw):
     entryIndex =  1 + (self.index(END) or 0)
     if entryIndex % AutoBreakMenu.MAX_ENTRIES == 0:
       cnf.update(kw)
       cnf['columnbreak'] = 1
       kw = {}
     return Menu.add(self, itemType, cnf, **kw)



if __name__ == '__main__':
   root = Tk()

   menubar = Menu(root)

   def fillMenu(menu):
     for i in xrange(100):
       menu.add_command(label=str(i), command=root.quit)
     menu.add_command(label="Exit", command=root.quit)

   menu1 = LongMenu(menubar, tearoff=0)
   fillMenu(menu1)
   menu2 = AutoBreakMenu(menubar, tearoff=0)
   fillMenu(menu2)

   menubar.add_cascade(label="Test1", menu=menu1)
   menubar.add_cascade(label="Test2", menu=menu2)

   root.config(menu=menubar)

   root.mainloop()
------------------------------------------------------

If your application is more complicated than that (e.g if you insert menu  
entries after the first adds), you'll have to change the code above a bit,  
since it doesn't handle calls to insert at all. But you get the idea.

HTH
-- 
python -c "print ''.join([chr(154 - ord(c)) for c in  
'U(17zX(%,5.zmz5(17l8(%,5.Z*(93-965$l7+-'])"



More information about the Python-list mailing list