Python tkinter - 如何使用字典制作两个链接的组合框

Python tkinter - How to make two linked combo boxes using a dictionary

目的:两个链接的组合框,一个显示字典键。另一个显示所选键的值。

我已经用字典键的值填充了第一个组合框,并将其转换为列表,以便在组合框中很好地显示。 已设置默认值,用于收集第二个组合框所需的数据。这里一切正常,我卡住的地方是如何更新 当第一个组合框当前值更改时第二个组合框的值。

到目前为止的代码

from tkinter import Tk, StringVar, ttk

dict_values = {
    "Beer": ["Ale", "Lager", "Stout"],
    "Spirits": ["Brandy", "Gin", "Rum"],
    "Wine": ["White","Red","Rose"]
}

#convert keys to list for displaying in the first combobox
box1= []
for key in dict_values:
    box1.append(key)

from tkinter import Tk, StringVar, ttk

class Application:

    def __init__(self, parent):
        self.parent = parent
        self.combo()
        
    def combo(self):
        #First Combobox
        self.box_value = StringVar()
        self.box = ttk.Combobox(self.parent, textvariable=self.box_value, 
                                state='readonly')
        self.box['values'] = box1
        self.box.current(0)
        self.box.grid(column=0, row=0)
        
        #Second Combobox
        self.box_value2 = StringVar()
        self.box2 = ttk.Combobox(self.parent, textvariable=self.box_value2, 
                                state='readonly')
        self.box2['values'] = dict_values[self.box.get()]
      
        self.box2.grid(column=1, row=0)

if __name__ == '__main__':
    root = Tk()
    root.minsize(800, 600) 
    app = Application(root)
    root.mainloop()

代码缺少将 <<ComboboxSelected>> 事件绑定到将在 self.box

中进行选择时执行的回调

所以添加

self.box.bind("<<ComboboxSelected>>",self.selected) 注意 self.selected 是你必须实现的新方法,这里是一个例子

    def selected(self,e):
        #print('selected value ->',self.box.get(),self.box_value.get())
        self.box2.configure(values = dict_values[self.box_value.get()] )
        self.box2.current(0)

完整代码

#<<ComboboxSelected>>
from tkinter import Tk, StringVar, ttk

dict_values = {
    "Beer": ["Ale", "Lager", "Stout"],
    "Spirits": ["Brandy", "Gin", "Rum"],
    "Wine": ["White","Red","Rose"]
}

#convert keys to list for displaying in the first combobox
box1= []
for key in dict_values:
    box1.append(key)

from tkinter import Tk, StringVar, ttk

class Application:

    def __init__(self, parent):
        self.parent = parent
        self.combo()

    # Modification 2
    def selected(self,e):
        #print('selected value ->',self.box.get(),self.box_value.get())
        self.box2.configure(values = dict_values[self.box_value.get()] )
        self.box2.current(0)


    def combo(self):
        #First Combobox
        self.box_value = StringVar()
        self.box = ttk.Combobox(self.parent, textvariable=self.box_value,
                                state='readonly')
        # Modification 1
        self.box.bind("<<ComboboxSelected>>",self.selected)
        self.box['values'] = box1
        self.box.current(0)
        self.box.grid(column=0, row=0)

        #Second Combobox
        self.box_value2 = StringVar()
        self.box2 = ttk.Combobox(self.parent, textvariable=self.box_value2,
                                state='readonly')
        self.box2['values'] = dict_values[self.box.get()]

        self.box2.grid(column=1, row=0)

if __name__ == '__main__':
    root = Tk()
    root.minsize(800, 600)
    app = Application(root)
    root.mainloop()

您可以使用 validatevalidatecommand 来完成此操作。无需向组合框添加 bind。如果 validate 设置为 "all""focus"

,则每次单击组合框时 validatecommand 都会 运行

A StringVar 是不必要的开销,您的文档结构有点奇怪。下面的示例解决了这些问题并为您的问题提供了解决方案。

from tkinter import Tk
from tkinter.ttk import Combobox

class Application(Tk):
    def __init__(self, *args, **kwargs):
        Tk.__init__(self,  *args, **kwargs)
        
        self.options = {
            "Beer": ["Ale", "Lager", "Stout"],
            "Spirits": ["Brandy", "Gin", "Rum"],
            "Wine": ["White","Red","Rose"]
        }
        
        #delegate between init and config so the Combobox kwargs are not a mile long
        self.cb1 = Combobox(self, state="readonly", values=[*self.options])
        self.cb1.config(validate="focus", validatecommand=self.populate_slave)
        
        self.cb1.current(0)
        self.cb1.grid(column=0, row=0)
        
        self.cb2 = Combobox(self, state="readonly")
        self.cb2.grid(column=1, row=0)

        #manually run the validatecommand function once to init cb2 items
        #this way it will always be correct regardless of the item you start cb1 with
        self.populate_slave() 
        
    def populate_slave(self):
        self.cb2['values'] = self.options[self.cb1.get()]
        self.cb2.current(0)
        return True #must return True or validatecommand will quit
        

if __name__ == "__main__":
    app = Application()
    app.minsize(800, 600)
    app.title('My Application')
    app.mainloop()