Можно ли установить состояние кнопки с динамическим вызовом имени, используя ключи getattr и словаря (Python 2.7, Tkinter)?

Я создаю программу с графическим интерфейсом python Tkinter, содержащую кнопки, которые будут включены/отключены в зависимости от различных ситуаций. По этой причине я хочу обращаться к кнопкам динамически, а не использовать статические имена. Я создал глобальный словарь, который связывает строковые дескрипторы кнопок с логическим значением, указывающим их желаемое состояние (заполняется во время создания виджета, а значения dict изменяются по мере необходимости в программе), и еще один словарь внутри функции, связывающий те же строковые дескрипторы с имена объектов кнопок.

Поскольку я хочу динамически изменять состояния кнопок, имена объектов не жестко закодированы, вместо этого я пытаюсь использовать getattr с вызовом функции, возвращающим имя объекта с использованием функции словаря, описанной выше:

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

Функции buttonDisable и buttonEnable вызываются в другом месте программы в других функциях, которые запускаются при нажатии кнопки. Я мог бы просто придерживаться жестко закодированных имен виджетов и поместить множество операторов if в мою функцию buttonEnable, поскольку в настоящее время может быть только четыре кнопки, но я планирую расширить программу, добавив дополнительные кнопки, и я хочу отключить все кнопки во время чтобы избежать входа пользователя, когда программа занята, поэтому желательны динамические вызовы.

При первом вызове getattr(self.ObjectDictionary(i),config(state=DISABLED)) возникает ошибка:

AttributeError: Button instance has no attribute 'config(state=DISABLED)'

Но я бы подумал, что .config() является атрибутом объекта виджета? И следующая жестко запрограммированная строка замены self.Load_Manifest.config(state=DISABLED) работает по назначению, что, по моему мнению, должно быть эквивалентно getattr?


person Jack    schedule 06.10.2020    source источник
comment
Yex, config — это атрибут объекта виджета. "config(state=DISALBED)" не является атрибутом объекта виджета.   -  person Bryan Oakley    schedule 06.10.2020


Ответы (1)


Я бы подумал, что .config() является атрибутом объекта виджета?

Да, config — это атрибут объекта виджета. Однако строка "config(state=DISABLED)" не является атрибутом объекта виджета.

Если вы хотите вызвать метод configure виджета, хранящегося в словаре, вы делаете это точно так же, как если бы виджет был обычной переменной. Следующий пример разбивает его на два шага, чтобы проиллюстрировать это:

widget = ObjectDictionary(i)
widget.configure(state=DISABLED)
person Bryan Oakley    schedule 06.10.2020
comment
Ваше решение работает хорошо, большое спасибо! (реализован widget.config, а не widget.configure) Так нет ли способа передать параметры при вызове метода объекта через функцию getattr? - person Jack; 06.10.2020
comment
@ Джек: я не совсем понимаю твой вопрос. Вы не можете вызвать метод через функцию getattr. getattr просто возвращает атрибут. Вы можете вызвать этот атрибут с опциями. Например, вы можете сделать getattr(ObjectDictionary(i), "config")(state=DISABLED), хотя это кажется более запутанным, чем более простое ObjectDictionary(i).config(state=DISABLED). - person Bryan Oakley; 06.10.2020