TypeError: 'StringVar'对象不可迭代 -- tkinter ListBox()

0 投票
1 回答
21 浏览
提问于 2025-04-14 15:42

我正在用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 对象类型。

撰写回答