Используйте массивы или словари:
import tkinter as tk
from tkinter import ttk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wm_title("Choose Multiple Animals")
self._frame = None
class AnimalPage(ttk.Frame):
def __init__(self, master, controller):
tk.Frame.__init__(self, master)
self.master = master
self.config(relief='sunken', borderwidth=2)
self.pack(fill = "both", expand = False)
self.grid_rowconfigure(0, weight = 1)
self.grid_columnconfigure(0, weight = 1)
self.animalList = ['Cat', 'Dog', 'Bear']
self.choices = ['None', 'Animal1', 'Animal2', 'Animal3']
self.animal_vars = dict()
self.text_labels = dict()
self.popup_menus = dict()
self.chosenAnimals = {}
self.tkvar4 = tk.StringVar()
for i, animal in enumerate(self.animalList):
self.animal_vars[animal] = tk.StringVar(master)
self.animal_vars[animal].set('None')
self.text_labels[animal] = ttk.Label(self, text=animal)
self.text_labels[animal].grid(column=0, row = 5 + i, sticky = (tk.W), padx=5, pady=5)
self.popup_menus[animal] = ttk.OptionMenu(self, self.animal_vars[animal], *self.choices, command=lambda selected, my_animal=animal: self.testFunc(my_animal, selected))
self.popup_menus[animal].grid(column=1, row = 5 + i, sticky = (tk.W, tk.E), padx=5, pady=5)
self.textLabel4 = ttk.Label(self, text=self.tkvar4.get())
self.textLabel4.grid(column=0, row = 8, sticky = (tk.W, tk.E), padx=5, pady=5)
def testFunc(self, animal, selection):
self.chosenAnimals.update({animal: selection})
self.configure()
def configure(self):
self.printout = ["{} is the {}".format(k, v) for (k,v) in self.chosenAnimals.items()]
self.tkvar4.set(self.printout)
self.textLabel4.config(text = self.tkvar4.get())
Поскольку вы в основном перебираете animalList
для динамического создания Label
s и OptionMenu
, вы можете также использоватьdict
или list
, чтобы помочь вам управлять и перебирать объекты.
После того, как вы настроили dict
или list
, теперь вы можете назначать / добавлять созданные вами виджеты tk.и ссылаться обратно легко.Лично в вашем примере я предпочитаю dict
, поскольку каждое животное имеет осмысленное имя, с которым его легче отлаживать (поиск self.text_labels['Cat']
будет проще, чем self.text_labels[0]
)
Также вы можете использоватьlambda
, чтобы обойти ограничение command=...
в виджетах tk.Таким образом, вы передаете имя животного обратно в функцию, поэтому вам не нужно определять его для каждого животного.
В качестве отступления в идеале я бы предложил вам дать своим объектам более осмысленные имена.Держитесь подальше от таких терминов, как textLabel4
или tkvar4
, чтобы легче было понять код.
Важное примечание:
Чтобы lambda
работал в цикле, вам потребуется повторныйanimal
будет параметром по умолчанию, а не непосредственно внутри lambda
, быстрое демо:
def func(v):
print(v)
x = list(range(3))
for i in range(len(x)):
x[i] = lambda: func(i)
x[0]
# 2
Можно ожидать, что x[0]
приведет к печати 0
, но на самом деле это будет2
, и это будет тот же результат через x[0:2]
.Причина в том, что когда лямбда назначается, она ссылается на объект i
вместо значения [0, 1, 2]
в каждой итерации.Следовательно, поскольку цикл завершился, i = 2
и ваши x
функции будут всегда печатать 2
.
Однако, если вы передали i
в качестве параметра по умолчанию в лямбда-выражении, значение будет передано:
x[i] = lambda y=i: func(y)
x[0]()
# 0
В связи с этим, причина, по которой я использовал lambda selected, my_animal=animal:...
, заключается в том, что command=...
в OptionMenu
всегда передает его variable
(который в данном случае является выбранным Animal1, Animal2 ...) в качестве первого параметра функции.
Надеюсь, это немного прояснит ситуацию.