TypeError: 'StringVar'对象不可迭代 -- tkinter ListBox()
我正在用Python制作一个流行的聚会游戏,并且使用tkinter来搭建设置界面,里面有玩家名字和游戏偏好选项。当我运行代码时,窗口打开了,看起来没问题,但有一个关键的地方出错了。
界面上有单选按钮可以选择牌组类型,还有一个列表框用来显示游戏中牌组的名字,应该在每次点击单选按钮时更新这个列表。
在命令行中获取牌组名字的列表是没问题的,但在图形界面中我却搞不定。
问题是,当窗口加载时,列表中只显示了第一个牌组的名字。当我点击单选按钮时,控制台会出现错误。
TypeError: 'StringVar' object is not iterable
我相信我一定遗漏了什么简单的东西。以下是相关的代码:
master_deck_list = []
deck_type_selection = tk.StringVar(value="official")
with open('cah-cards-full.json', encoding="utf8") as c:
master_deck_list = json.loads(c.read())
def get_available_decks(master_deck_list, deck_type_selection):
# Assign the list of deck names to deck_list
decks_list = []
for av_deck in master_deck_list:
if deck_type_selection == 'official':
if av_deck['official'] == True:
decks_list.append(av_deck['name'])
elif deck_type_selection == 'community':
if av_deck['official'] == False:
decks_list.append(av_deck['name'])
elif deck_type_selection == 'all':
decks_list.append(av_deck['name'])
return decks_list
decklist = get_available_decks(master_deck_list, deck_type_selection="official")
list_items = tk.StringVar(value=decklist)
def update_decklist(list_items):
for item in list_items:
listbox.insert(tk.END, item)
...
# Deck type radio buttons
radio_1 = tk.Radiobutton(decktypes_frame, text="Official", variable=deck_type_selection, value="official", command=lambda: update_decklist(list_items))
radio_1.grid(column=0, row=0, padx=5, pady=5)
radio_2 = tk.Radiobutton(decktypes_frame, text="Community", variable=deck_type_selection, value="community", command=lambda: update_decklist(list_items))
radio_2.grid(column=1, row=0, padx=5, pady=5)
radio_3 = tk.Radiobutton(decktypes_frame, text="All", variable=deck_type_selection, value="all", command=lambda: update_decklist(list_items))
radio_3.grid(column=2, row=0, padx=5, pady=5)
# decksframe holds the available and selected decks lists
decksframe = tk.LabelFrame(main, text="Available Decks")
decksframe.columnconfigure(0, weight=3)
decksframe.columnconfigure(1, weight=3)
# Available Decks
listbox = tk.Listbox(decksframe, selectmode="multiple", listvariable=list_items, exportselection=0)
listbox.grid(column=0, row=0, padx=5, pady=5)
这是完整的错误追踪信息(谢谢你,Michael):
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.2800.0_x64__qbz5n2kfra8p0\lib\tkinter\__init__.py", line 1892, in __call__
return self.func(*args)
File "setup.py", line 63, in <lambda>
radio_2 = tk.Radiobutton(decktypes_frame, text="Community", variable=deck_type_selection, value="community", command=lambda: update_decklist(list_items))
File "setup.py", line 40, in update_decklist
for item in list_items:
TypeError: 'StringVar' object is not iterable
1 个回答
1
这个错误信息的意思很简单。list_items
不是一个列表,也不是一个字符串,它是一个 StringVar
。你不能用 for item in list_items
这样的方式来遍历,因为 StringVar
不是可以被循环的东西。
解决办法似乎很简单,就是把 list_items
直接设置为 decklist
(或者干脆把 list_items
丢掉,直接使用 decklist
)。然后,把项目插入到列表框中,而不是使用 listvariable
。比如:
listbox = tk.Listbox(decksframe, selectmode="multiple", exportselection=0)
listbox.insert("end", *decklist)
使用 listvariable
在 Tcl 中效果要比在 Python 中好,因为 tkinter 没有内置的 ListVar
对象类型。