Tkinter Создать OptionMenus с помощью цикла

Я создал код для создания tkinter OptionMenus со значениями в словаре с помощью цикла for. Код, кажется, работает успешно, при этом OptionMenus отображается с ключевыми словами в окне по желанию ...

import tkinter as tk
from tkinter import *

class Example:

    def __init__(self): 
        #Dictionary with categories and their relative keywords
        self.categorykeywords={"Category 1":["Keyword 1", "Keyword 2", "Keyword 3"], "Category 2":["Keyword A","Keyword B","Keyword C"], "Category 3":["Another Keyword"]}

        #Dictionary containing the option menus referenced by category name
        btn_dict={}

        #Storing tkvar variable for later referencing
        self.dropdownreference={}

        #Number to assign to the tkvar name, to make the unique variables for each category
        i=1
        columncounter=0

        for category in self.categorykeywords:
            #Creating a unique variable / name for later reference
            exec('self.tkvar_' + str(i) + ' = ' + 'StringVar(root)') 

            #Creating OptionMenu with unique variable
            btn_dict[category] = tk.OptionMenu(root, exec('variable=self.tkvar_'+str(i)), *self.categorykeywords[category])

            btn_dict[category].grid(row=0, column=columncounter, padx=1, pady=1)

            #Storing the variable used for later use
            self.dropdownreference[category]=exec('variable=self.tkvar_'+str(i)) 

            columncounter+=1
            i+=1

root = Tk()
my_gui = Example()
root.mainloop()

Однако при их выборе я получаю сообщение об ошибке:

Traceback (most recent call last):
  File "c:\users\czuczor\appdata\local\programs\python\python36\lib\tkinter\__init__.py", line 1699, in __call__
    return self.func(*args)
  File "c:\users\czuczor\appdata\local\programs\python\python36\lib\tkinter\__init__.py", line 3434, in __call__
    self.__var.set(self.__value)
AttributeError: 'NoneType' object has no attribute 'set'

Я предполагаю, что у него проблемы с фактическим назначением переменной или, возможно, даже с отображением выбранного ключевого слова. Я получаю ту же ошибку при попытке использовать ttk.OptionMenu, который автоматически отображает первое значение. Есть какие нибудь идеи как это починить?


person Erico9001    schedule 23.03.2018    source источник
comment
Избавьтесь от всего этого exec ужаса и научитесь пользоваться словарями из любви ко всему святому.   -  person Aran-Fey    schedule 23.03.2018
comment
Не импортируйте tkinter дважды. Удалите from tkinter import * и просто оставьте import tkinter as tk. Также не очень экономно использовать exec. Вам следует избегать этого метода.   -  person Mike - SMT    schedule 23.03.2018
comment
@ Аран-Фей, вы говорите, что проблема только в команде exec? Честно говоря, меня не волнует, «ужас» это или «нечестивый». Мне просто нужно что-то работающее. Кроме того, я знаю, как пользоваться словарями, что должно быть ясно из примера. Ты мне не помог.   -  person Erico9001    schedule 23.03.2018
comment
Да, проблема в командах exec. Почему вы не используете словари вместо exec?   -  person Aran-Fey    schedule 23.03.2018
comment
Видел, как это делает кто-то другой. Впервые в Python. Ответил скорректированным кодом.   -  person Erico9001    schedule 23.03.2018
comment
Я не собирался быть резким. (Скорее, резкость была направлена ​​не на вас.) Это безответственное использование exec и eval заставляет новичков вроде вас думать, что они правильный инструмент для работы, что сводит меня с ума. Могу я спросить, откуда у вас эта exec идея, чтобы я мог проголосовать против них и отозвать их лицензию программиста?   -  person Aran-Fey    schedule 23.03.2018


Ответы (1)


Благодаря комментариям, вот проблема, решенная путем использования словаря для определения переменной вместо команды exec.

import tkinter as tk

class Example:

    def __init__(self): 
        #Dictionary with categories and their relative keywords
        self.categorykeywords={"Category 1":["Keyword 1", "Keyword 2", "Keyword 3"], "Category 2":["Keyword A","Keyword B","Keyword C"], "Category 3":["Another Keyword"]}

        #Dictionary containing the option menus referenced by category name
        btn_dict={}

        #Storing tkvar variable for later referencing
        self.dropdownreference={}

        #Number to assign to the tkvar name, to make the unique variables for each category
        i=1
        columncounter=0

        for category in self.categorykeywords:
            #Creating a unique variable / name for later reference
            self.dropdownreference[category] = StringVar(root)

            #Creating OptionMenu with unique variable
            btn_dict[category] = tk.OptionMenu(root, self.dropdownreference[category], *self.categorykeywords[category])

            btn_dict[category].grid(row=0, column=columncounter, padx=1, pady=1)

            columncounter+=1
            i+=1

root = Tk()
my_gui = Example()
root.mainloop()
person Erico9001    schedule 23.03.2018