Reputation: 47
I am having issues with creating a menu that suits the needs of my application. I am creating an app that requires the user to choose possible items to compare inside of a source menu.
Right now my menu organization is indended to look something like
FILE | EDIT | OPTIONS | SOURCE | HELP
My issue is, the number of choices inside source is quite large (~100) and needs to be navicable quickly (<5 seconds) or the target audience of my application will probably not use it.
The solution I have in mind is to nest options underneath the data structures they come from. Effectively this means I can treat the Source options and suboptions as two lists:
["Data1", "Data2", "Data3"]
and
[["Option1_1", "Option1_2", "Option1_3"],
["Option2_1","Option2_2","Option2_3"],
["Option3_1","Option3_2","Option3_3"]]
I have searched extensively and can't find how to create submenus effectively in Tkinter. When I get a submenu of radiobuttons (checkbuttons would also work), the button click does not activate the command, and that is not a viable solution.
What I would like to do is create a menu that looks something like
FILE | SOURCE | ETC...
Data1 |
Option1_1
Option1_2
Option1_3
Data2 |
Data3
How can I do this? Preferably while also storing buttons to a list, then appending them to the menu, so that I can call select and deselect if I need to? Radiobuttons or checkbuttons would work, checkbuttons are preferred provided I still have access to them after creation.
Thank you
Here's one example of non-working code:
from Tkinter import *
class App(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.makeMenu(master)
def makeMenu(self, parent):
menuBar = Frame(parent, relief = 'raised', borderwidth = 1)
fileMenu = Menubutton(menuBar, text = "File")
fileMenu.pack(side = 'left')
fileMenu.menu = Menu(fileMenu, tearoff = 0)
load = Menubutton(fileMenu.menu, text="Load")
load.pack(anchor=W)
source = Menubutton(fileMenu.menu, text="Source")
source.pack(anchor=W)
source.menu = Menu(source, tearoff = 0)
self._listi = ["who", "what", "where", "how"]
self._buttonList = []
for l in self._listi:
c = Checkbutton(master = source.menu, text=l, command=lambda arg0=l: self.test(arg0))
self._buttonList.append([l, c])
c.pack()
save = Button(master=fileMenu.menu, text="Save")
save.pack(anchor=W)
exit = Button(master=fileMenu.menu, text="Exit", command = self.quit)
exit.pack()
fileMenu['menu'] = fileMenu.menu
menuBar.pack()
def test(self, arg0):
for b in self._buttonList:
if arg0 != b[0]:
b[1].deselect()
elif arg0 == b[0]:
b[1].select()
# create app
myApp = App()
# start program
myApp.mainloop()
Upvotes: 0
Views: 1928
Reputation: 386332
You cannot add Checkbutton
or Button
instances to a menu. You must use the add_checkbutton
or add_radiobutton
or add_command
methods. Also, you don't need to create a menubar from a frame and menubuttons -- you can attach a menu directly to a window. Also, you don't need to programatically select or deselect the checkbuttons or radiobuttons, that is taken care of by tkinter.
I've modified your code to illustrate:
from Tkinter import *
class App(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.makeMenu(master)
def makeMenu(self, parent):
menuBar = Menu(parent)
parent.configure(menu=menuBar)
fileMenu = Menu(menuBar)
sourceMenu = Menu(menuBar)
menuBar.add_cascade(label="File", menu=fileMenu)
fileMenu.add_command(label="Load")
fileMenu.add_cascade(label="Source", menu=sourceMenu)
self._listi = ["who","what","where","how"]
for l in self._listi:
sourceMenu.add_checkbutton(label=l, command=lambda arg0=l: self.test(arg0))
fileMenu.add_command(label="Save")
fileMenu.add_command(label="Exit", command=self.quit)
def test(self, arg0):
print "you clicked on", arg0
# create app
root = Tk()
myApp = App(root)
# start program
myApp.mainloop()
Note that I also added a line of code to create the root window, and I pass that root window into the constructor for the app.
Upvotes: 1