Long Tkinter Menu

D

Dustan

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).

As for why I'm creating such a long menu, think browser bookmarks
(That's not actually what I'm doing, but similar).

================================
# menu-example-5.py

from Tkinter import *

root = Tk()

menubar = Menu(root)

menu = Menu(menubar, tearoff=0)
for i in xrange(100):
menu.add_command(label=str(i), command=root.quit)
menu.add_command(label="Exit", command=root.quit)

menubar.add_cascade(label="Test", menu=menu)

root.config(menu=menubar)

mainloop()
================================
 
E

Eric Brunel

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
 
D

Dustan

Eric said:
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

Thanks, I'll see what I can do with that.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top