I'm building a python Tkinter GUI program containing buttons which will be enabled/disabled depending on various situations. For this reason, I want to refer to buttons dynamically rather than using static names. I've built a global dictionary that links button string descriptors to a Boolean value indicating their desired state (populated during widget creation, and dict values altered as required throughout the program), and another dictionary inside a function linking the same string descriptors to the button object names.
Since I wish to change button states dynamically, the object names aren't hardcoded, instead I'm trying to use getattr with a function call returning the object name using the dictionary function described above:
class WApplication(Frame):
buttonStates={}
...
def buttonDisable(self):
for i in self.buttonStates:
#self.Load_Manifest.config(state=DISABLED) #This line works (i.e., visibly disables the 'Load Manifest' button)
#print(i+".config(state=DISABLED)") #Output: Load_Manifest.config(state=DISABLED)
getattr(self.ObjectDictionary(i),"config(state=DISABLED)") #AttributeError: Button instance has no attribute 'config(state=DISABLED)'
def buttonEnable(self): #Similar error encountered as above when debugging this function
for i in self.buttonStates:
if self.buttonStates[i]==True:
getattr(self.ObjectDictionary(i),"config(state=NORMAL)")
...
def ObjectDictionary(self,string):
"Function that maps dictionary widget keys to their object titles and returns the mapped object title"
switcher={
"Load_Manifest":self.Load_Manifest,
"Update_Manifest":self.Update_Manifest,
"Fresh_Manifest":self.Fresh_Manifest,
"Manifest_Details":self.Manifest_Details
}
return switcher.get(string)
...
def createWidgets(self):
self.QUIT = Button(self.master)
self.QUIT["text"] = "QUIT"
self.QUIT["fg"] = "red"
self.QUIT["command"] = self.quit
self.QUIT.place(x=710,y=10,height=50,width=100)
self.Load_Manifest=Button(self.master)
self.Load_Manifest["text"]="Load Manifest"
self.Load_Manifest["command"]=self.LoadManifestButton
self.Load_Manifest.config(state=NORMAL)
self.Load_Manifest.place(x=10,y=10,height=50,width=110)
self.buttonStates["Load_Manifest"]=True
self.buttonActions["Load_Manifest"]=False
self.Update_Manifest=Button(self.master)
self.Update_Manifest["text"]="Update Manifest"
self.Update_Manifest["command"]=self.UpdateManifestButton
self.Update_Manifest.config(state=DISABLED)
self.Update_Manifest.place(x=130,y=10,height=50,width=120)
self.buttonStates["Update_Manifest"]=False
self.buttonActions["Update_Manifest"]=False
self.Fresh_Manifest=Button(self.master)
self.Fresh_Manifest["text"]="Create New Manifest"
self.Fresh_Manifest["command"]=self.FreshManifestWindowButton
self.Fresh_Manifest.config(state=NORMAL)
self.Fresh_Manifest.place(x=260,y=10,height=50,width=150)
self.buttonStates["Fresh_Manifest"]=True
self.buttonActions["Fresh_Manifest"]=False
...
self.Manifest_Details=Button(self.master)
self.Manifest_Details["text"]="Details"
self.Manifest_Details["command"]=self.ManifestDetailsButton
self.Manifest_Details.config(state=DISABLED)
self.Manifest_Details.place(x=10,y=790,height=50,width=100)
self.buttonStates["Manifest_Details"]=False
self.buttonActions["Manifest_Details"]=False
...
The buttonDisable and buttonEnable functions are called elsewhere in the program in other functions that are run during button presses. I could just stick to hardcoded widget names and put a load of if statements in my buttonEnable function since there may only be four buttons currently, but I plan on expanding the program adding more with additional buttons, and I wish to disable all buttons during an operation to avoid user entry when the program is busy, so therefore dynamic calls are desired.
During the first call of getattr(self.ObjectDictionary(i),"config(state=DISABLED)") an error is raised:
AttributeError: Button instance has no attribute 'config(state=DISABLED)'
But I would have thought .config() is an attribute of a widget object? And the following hardcoded substitute line self.Load_Manifest.config(state=DISABLED) works as intended, which by my understanding of getattr should be equivalent?
I would have thought .config() is an attribute of a widget object?
Yes, config
is an attribute of a widget object. However, the string "config(state=DISABLED)"
is not an attribute of a widget object.
If you want to call the configure method of a widget stored in a dictionary, you do it exactly like you would if the widget was a regular variable. The following example breaks it down into two steps to illustrate the point:
widget = ObjectDictionary(i)
widget.configure(state=DISABLED)