Reputation: 1375
I'm new to python and I'm trying to change dynamically button's text and command to make sub-menus. here's my code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import tkinter
class Display(tkinter.Tk):
def __init__(self,parent):
tkinter.Tk.__init__(self,parent)
self.parent = parent
self.GuiDisplay()
def GuiDisplay(self):
self.grid()
self.geometry("1280x720")
#self.overrideredirect(True) #uncomment for fullscreen
"""Build the GUI"""
MessageDisplay = tkinter.Label(self, text = 'No messages from slaves', anchor = 'nw', justify = 'left', relief = 'ridge', font = ("Courier New", 15), bg = '#e4e7e8', fg = '#2980b9')
MessageDisplay.grid(row = 0, column = 0, columnspan = 3, sticky = 'wens', ipadx = 2, ipady = 2)
ClockDisplay = tkinter.Label(self, text = '00:00', relief = 'ridge', font = ("Courier New", 40), bg = '#e4e7e8', fg = '#2980b9')
ClockDisplay.grid(row = 0, column = 3, sticky = 'wens', ipadx = 2, ipady = 2)
Menu1Button = tkinter.Button(self, text = 'Ring', command = self.Action(Do = 'Rng'), font = ("Courier New", 20), bg = '#3498db', fg = '#e4e7e8', activebackground = '#2980b9', activeforeground = '#e4e7e8')
Menu1Button.grid(row = 1, column = 0, columnspan = 2, sticky = 'wens', padx = 2, ipadx = 4)
Menu2Button = tkinter.Button(self, text = 'Toggle holliday mode', command = self.Action(Do = 'SwHolDay'), font = ("Courier New", 20), bg = '#3498db', fg = '#e4e7e8', activebackground = '#2980b9', activeforeground = '#e4e7e8')
Menu2Button.grid(row = 2, column = 0, columnspan = 2, sticky = 'wens', padx = 2, ipadx = 4)
Menu3Button = tkinter.Button(self, text = 'Edit time', command = self.SetMenu(MenuIndex = 2), font = ("Courier New", 20), bg = '#3498db', fg = '#e4e7e8', activebackground = '#2980b9', activeforeground = '#e4e7e8')
Menu3Button.grid(row = 3, column = 0, columnspan = 2, sticky = 'wens', padx = 2, ipadx = 4)
Menu4Button = tkinter.Button(self, text = 'Add/Edit alarms', command = self.SetMenu(MenuIndex = 3), font = ("Courier New", 20), bg = '#3498db', fg = '#e4e7e8', activebackground = '#2980b9', activeforeground = '#e4e7e8')
Menu4Button.grid(row = 4, column = 0, columnspan = 2, sticky = 'wens', padx = 2, ipadx = 4)
Menu5Button = tkinter.Button(self, text = 'Shutdown', command = self.Action(Do = 'Shutdwn'), font = ("Courier New", 20), bg = '#3498db', fg = '#e4e7e8', activebackground = '#2980b9', activeforeground = '#e4e7e8')
Menu5Button.grid(row = 5, column = 0, columnspan = 2, sticky = 'wens', padx = 2, ipadx = 4)
MenuDescription = tkinter.Label(self, text = 'No menu selected.', anchor = 'nw', justify = 'left', relief = 'ridge', font = ("Courier New", 15), bg = '#e4e7e8', fg = '#2980b9')
MenuDescription.grid(column = 2, columnspan = 2, row = 1, rowspan = 5, sticky = 'wens', ipadx = 2, ipady = 2)
self.grid_columnconfigure(0, weight = 3)
self.grid_columnconfigure(1, weight = 3)
self.grid_columnconfigure(2, weight = 3)
self.grid_columnconfigure(3, weight = 1)
self.grid_rowconfigure(0, weight = 10)
self.grid_rowconfigure(1, weight = 18)
self.grid_rowconfigure(2, weight = 18)
self.grid_rowconfigure(3, weight = 18)
self.grid_rowconfigure(4, weight = 18)
self.grid_rowconfigure(5, weight = 18)
def SetMenu(self, MenuIndex):
if MenuIndex==1:
self.Menu1Button.configure(text = 'Ring', command = self.Action(Do = 'Rng'))
self.Menu2Button.configure(text = 'Toggle holliday mode', command = self.Action(Do = 'SwHolDay'))
self.Menu3Button.configure(text = 'Edit time', command = self.SetMenu(MenuIndex = 2))
self.Menu4Button.configure(text = 'Add/Edit alarms', command = self.SetMenu(MenuIndex = 3))
self.Menu5Button.configure(text = 'Shutdown', command = self.Action(Do = 'Shutdwn'))
elif MenuIndex==2:
self.Menu1Button.configure(text = 'Edit hours', command = self.Action(Do = 'ModH'))
self.Menu2Button.configure(text = 'Edit minutes', command = self.Action(Do = 'ModM'))
self.Menu3Button.configure(text = 'Edit seconds', command = self.Action(Do = 'ModS'))
self.Menu4Button.configure(text = 'Internet synchronization', command = self.Action(Do = 'Synch'))
self.Menu5Button.configure(text = 'Return to menu', command = self.SetMenu(MenuIndex = 1))
elif MenuIndex==3:
self.Menu1Button.configure(text = 'Edit hours', command = self.Action(Do = 'ModHA'))
self.Menu2Button.configure(text = 'Edit minutes', command = self.Action(Do = 'ModMA'))
self.Menu3Button.configure(text = 'Edit seconds', command = self.Action(Do = 'ModSA'))
self.Menu4Button.configure(text = 'Switch mode', command = self.Action(Do = 'ChMod'))
self.Menu5Button.configure(text = 'Return to menu', command = self.SetMenu(MenuIndex = 1))
def Action(self, Do):
pass
if __name__ == "__main__":
app = Display(None)
app.title('Web Bell')
app.mainloop()
and the traceback for the error is
File "\\uranus\faure\Bureau\project\webBell.py", line 80, in <module>
app = Display(None)
File "\\uranus\faure\Bureau\project\webBell.py", line 10, in __init__
self.GuiDisplay()
File "\\uranus\faure\Bureau\project\webBell.py", line 32, in GuiDisplay
Menu3Button = tkinter.Button(self, text = 'Edit time', command = self.SetMenu(MenuIndex = 2), font = ("Courier New", 20), bg = '#3498db', fg = '#e4e7e8', activebackground = '#2980b9', activeforeground = '#e4e7e8')
File "\\uranus\faure\Bureau\project\webBell.py", line 64, in SetMenu
self.Menu1Button.configure(text = 'Edit hours', command = self.Action(Do = 'ModH'))
File "C:\Python33\lib\tkinter\__init__.py", line 1867, in __getattr__
return getattr(self.tk, attr)
AttributeError: 'tkapp' object has no attribute 'Menu1Button'
I guess it come from the "self" in the SetMenu function but I tried without and it still didn't works.
EDIT: updated code
#!/usr/bin/python
# -*- coding: utf-8 -*-
import tkinter
class Display(tkinter.Tk):
def __init__(self,parent):
tkinter.Tk.__init__(self,parent)
self.parent = parent
self.GuiDisplay()
def GuiDisplay(self):
self.grid()
self.geometry("1280x720")
#self.overrideredirect(True) #uncomment for fullscreen
"""Build the GUI"""
self.MessageDisplay = tkinter.Label(self, text = 'No messages from slaves', anchor = 'nw', justify = 'left', relief = 'ridge', font = ("Courier New", 15), bg = '#e4e7e8', fg = '#2980b9')
self.MessageDisplay.grid(row = 0, column = 0, columnspan = 3, sticky = 'wens', ipadx = 2, ipady = 2)
self.ClockDisplay = tkinter.Label(self, text = '00:00', relief = 'ridge', font = ("Courier New", 40), bg = '#e4e7e8', fg = '#2980b9')
self.ClockDisplay.grid(row = 0, column = 3, sticky = 'wens', ipadx = 2, ipady = 2)
self.Menu1Button = tkinter.Button(self, text = 'Ring', command = self.Action(Do = 'Rng'), font = ("Courier New", 20), bg = '#3498db', fg = '#e4e7e8', activebackground = '#2980b9', activeforeground = '#e4e7e8')
self.Menu1Button.grid(row = 1, column = 0, columnspan = 2, sticky = 'wens', padx = 2, ipadx = 4)
self.Menu2Button = tkinter.Button(self, text = 'Toggle holliday mode', command = self.Action(Do = 'SwHolDay'), font = ("Courier New", 20), bg = '#3498db', fg = '#e4e7e8', activebackground = '#2980b9', activeforeground = '#e4e7e8')
self.Menu2Button.grid(row = 2, column = 0, columnspan = 2, sticky = 'wens', padx = 2, ipadx = 4)
self.Menu3Button = tkinter.Button(self, text = 'Edit time', command = self.SetMenu(MenuIndex = 2), font = ("Courier New", 20), bg = '#3498db', fg = '#e4e7e8', activebackground = '#2980b9', activeforeground = '#e4e7e8')
self.Menu3Button.grid(row = 3, column = 0, columnspan = 2, sticky = 'wens', padx = 2, ipadx = 4)
self.Menu4Button = tkinter.Button(self, text = 'Add/Edit alarms', command = self.SetMenu(MenuIndex = 3), font = ("Courier New", 20), bg = '#3498db', fg = '#e4e7e8', activebackground = '#2980b9', activeforeground = '#e4e7e8')
self.Menu4Button.grid(row = 4, column = 0, columnspan = 2, sticky = 'wens', padx = 2, ipadx = 4)
self.Menu5Button = tkinter.Button(self, text = 'Shutdown', command = self.Action(Do = 'Shutdwn'), font = ("Courier New", 20), bg = '#3498db', fg = '#e4e7e8', activebackground = '#2980b9', activeforeground = '#e4e7e8')
self.Menu5Button.grid(row = 5, column = 0, columnspan = 2, sticky = 'wens', padx = 2, ipadx = 4)
self.MenuDescription = tkinter.Label(self, text = 'No menu selected.', anchor = 'nw', justify = 'left', relief = 'ridge', font = ("Courier New", 15), bg = '#e4e7e8', fg = '#2980b9')
self.MenuDescription.grid(column = 2, columnspan = 2, row = 1, rowspan = 5, sticky = 'wens', ipadx = 2, ipady = 2)
self.grid_columnconfigure(0, weight = 3)
self.grid_columnconfigure(1, weight = 3)
self.grid_columnconfigure(2, weight = 3)
self.grid_columnconfigure(3, weight = 1)
self.grid_rowconfigure(0, weight = 10)
self.grid_rowconfigure(1, weight = 18)
self.grid_rowconfigure(2, weight = 18)
self.grid_rowconfigure(3, weight = 18)
self.grid_rowconfigure(4, weight = 18)
self.grid_rowconfigure(5, weight = 18)
def SetMenu(self, MenuIndex):
if MenuIndex==1:
self.Menu1Button.configure(text = 'Ring', command = self.Action(Do = 'Rng'))
self.Menu2Button.configure(text = 'Toggle holliday mode', command = self.Action(Do = 'SwHolDay'))
self.Menu3Button.configure(text = 'Edit time', command = self.SetMenu(MenuIndex = 2))
self.Menu4Button.configure(text = 'Add/Edit alarms', command = self.SetMenu(MenuIndex = 3))
self.Menu5Button.configure(text = 'Shutdown', command = self.Action(Do = 'Shutdwn'))
elif MenuIndex==2:
self.Menu1Button.configure(text = 'Edit hours', command = self.Action(Do = 'ModH'))
self.Menu2Button.configure(text = 'Edit minutes', command = self.Action(Do = 'ModM'))
self.Menu3Button.configure(text = 'Edit seconds', command = self.Action(Do = 'ModS'))
self.Menu4Button.configure(text = 'Internet synchronization', command = self.Action(Do = 'Synch'))
self.Menu5Button.configure(text = 'Return to menu', command = self.SetMenu(MenuIndex = 1))
elif MenuIndex==3:
self.Menu1Button.configure(text = 'Edit hours', command = self.Action(Do = 'ModHA'))
self.Menu2Button.configure(text = 'Edit minutes', command = self.Action(Do = 'ModMA'))
self.Menu3Button.configure(text = 'Edit seconds', command = self.Action(Do = 'ModSA'))
self.Menu4Button.configure(text = 'Switch mode', command = self.Action(Do = 'ChMod'))
self.Menu5Button.configure(text = 'Return to menu', command = self.SetMenu(MenuIndex = 1))
def Action(self, Do):
pass
if __name__ == "__main__":
app = Display(None)
app.title('Web Bell')
app.mainloop()
Upvotes: 0
Views: 5363
Reputation: 7842
You have not defined Menu1Button
as a class attribute, so it is only scoped inside your __init__
. It should be defined as:
self.Menu1Button = tkinter.Button(self, text = 'Ring', command = self.Action(Do = 'Rng'), font = ("Courier New", 20), bg = '#3498db', fg = '#e4e7e8', activebackground = '#2980b9', activeforeground = '#e4e7e8')
self.Menu1Button.grid(row = 1, column = 0, columnspan = 2, sticky = 'wens', padx = 2, ipadx = 4)
The same goes for all the other widgets defined inside your constructor.
EDIT:
So now that that first problem is fixed the issue becomes much clearer. You are defining the command attribute of your widgets incorrectly.
For example, for self.Menu3Button
you define the command as self.SetMenu(MenuIndex = 2)
. In python this will try and execute the function self.SetMenu
with the argument 2
(sidebar: you don't need to do MenuIndex=2
, just 2
is fine) when it first gets to it. This causes the function SetMenu
to execute before Menu3Button
has been defined as a class attribute. Hence python cannot find the attribute and you get an AttributeError
.
The command
passed to the widget should be a function instance. For example:
# an example function
def printit(val):
print val
# This is NOT valid
command = printit("hello!")
# This is valid
command = lambda:printit("hello!")
In the valid case we are passing a partial function (i.e. a half formed function where the arguments are already attached):
In [29]: printit("direct call")
direct call
In [30]: partial_printit = lambda:printit("partial call")
In [31]: partial_printit()
partial call
So in your case:
command = self.SetMenu(MenuIndex = 2)
becomes
command = lambda:self.SetMenu(MenuIndex = 2)
This is the same for all the command
keywords for all your widgets.
For more info on lambda functions, see here: https://docs.python.org/2/tutorial/controlflow.html#lambda-expressions
Upvotes: 2