Home > OS >  Multiple Dependent Dropdowns in Tkinter
Multiple Dependent Dropdowns in Tkinter

Time:08-05

I am trying to create dropdown lists for a manufacturing workflow that are dependent on each previous choice - Product, Operation, Room number, Equipment, etc. I was able to make the 1st and 2nd selections, but after I choose the operation, I am not sure how to proceed to make a list of rooms that would be dependent on the operation selected. I tried to use the code previously provided on the ask link: Drop down list dependent from another drop down tkinter But as I try to create a 3rd drop-down, it shows empty. How do I proceed?

import tkinter as tk

 

products = ["A","B","C","D"]

operation = [["aX","aY"],
          ["bX","bY"],
          ["cX","cY"],
          ["dX","dY"]]

room =[ [["axP","axQ"], ["ayP","ayQ"]],
            [["bxP","bxQ"], ["byP","byQ"]],
            [["cxP","cxQ"], ["cyP","cyQ"]],
            [["dxP","dxQ"], ["dyP","dyQ"]]]
           
root = tk.Tk()
canvas = tk.Canvas(root, height=1000, width= 1000, bg="white")
canvas.pack()


tkvar = tk.StringVar(root)
tkvar.set('Product')

tkvar2 = tk.StringVar(root)
tkvar2.set('Operation')

tkvar3 = tk.StringVar(root)
tkvar3.set('Room')


popupMenu1 = tk.OptionMenu(canvas, tkvar, *products)
popupMenu1.pack()

popupMenu2 = tk.OptionMenu(canvas, tkvar2, [])
popupMenu2.pack()

popupMenu3 = tk.OptionMenu(canvas, tkvar3, [])
popupMenu3.pack()



def change_dropdown(*args):
    print("Chosen product "   tkvar.get())

    for i in range(len(products)):

        if tkvar.get() == products[i]:
            popupMenu2["menu"].delete(0, "end")
            
            for item in operation[i]:

                popupMenu2['menu'].add_command(label=item, command=tk._setit(tkvar2, item))
                
                if tkvar2.get() == operation[i]:
                    popupMenu3["menu"].delete(0, "end")
            
                    for choice in operation[i]:
                        popupMenu3['menu'].add_command(label=choice, command=tk._setit(tkvar3, choice))

tkvar.trace('w', change_dropdown)

root.mainloop()

Greatly appreciate any help

CodePudding user response:

I am sure there is a nicer way to do this (Maybe with some dictionaries?), because like this you can easily confuse yourself with the indexing. However, the way you designed it right now it can be solved with a second function. Also for the operation and room you have a nested lists, so that is why you need the second for loop.

import tkinter as tk

products = ["A","B","C","D"]

operation = [["aX","aY"],
          ["bX","bY"],
          ["cX","cY"],
          ["dX","dY"]]

room =[ [["axP","axQ"], ["ayP","ayQ"]],
            [["bxP","bxQ"], ["byP","byQ"]],
            [["cxP","cxQ"], ["cyP","cyQ"]],
            [["dxP","dxQ"], ["dyP","dyQ"]]]
           
root = tk.Tk()
canvas = tk.Canvas(root, height=1000, width= 1000, bg="white")
canvas.pack()

tkvar = tk.StringVar(root)
tkvar.set('Product')

tkvar2 = tk.StringVar(root)
tkvar2.set('Operation')

tkvar3 = tk.StringVar(root)
tkvar3.set('Room')

popupMenu1 = tk.OptionMenu(canvas, tkvar, *products)
popupMenu1.pack()

popupMenu2 = tk.OptionMenu(canvas, tkvar2, [])
popupMenu2.pack()

popupMenu3 = tk.OptionMenu(canvas, tkvar3, [])
popupMenu3.pack()


def change_dropdown(*args):
    print("Chosen product "   tkvar.get())

    for i in range(len(products)):
        if tkvar.get() == products[i]:
            popupMenu2["menu"].delete(0, "end")

            for item in operation[i]:
                popupMenu2['menu'].add_command(label=item, command=tk._setit(tkvar2, item))


def change_dropdown2(*args):
    print("Chosen option "   tkvar2.get())

    for i in range(len(operation)):
        for j in range(len(operation[i])):
            if tkvar2.get() == operation[i][j]:
                popupMenu3["menu"].delete(0, "end")

                for choice in room[i][j]:
                    popupMenu3['menu'].add_command(label=choice, command=tk._setit(tkvar3, choice))


tkvar.trace('w', change_dropdown)
tkvar2.trace('w', change_dropdown2)

root.mainloop()

CodePudding user response:

You can use command option of OptionMenu instead of tracing tkinter variable:

import tkinter as tk

products = ["A","B","C","D"]

operation = [["aX","aY"],
             ["bX","bY"],
             ["cX","cY"],
             ["dX","dY"]]

room =[[["axP","axQ"], ["ayP","ayQ"]],
       [["bxP","bxQ"], ["byP","byQ"]],
       [["cxP","cxQ"], ["cyP","cyQ"]],
       [["dxP","dxQ"], ["dyP","dyQ"]]]

root = tk.Tk()
canvas = tk.Canvas(root, height=1000, width= 1000, bg="white")
canvas.pack()

tkvar = tk.StringVar(root)
tkvar.set('Product')

tkvar2 = tk.StringVar(root)
tkvar2.set('Operation')

tkvar3 = tk.StringVar(root)
tkvar3.set('Room')

def on_product_change(product):
    print("Chosen product", product)

    i = products.index(product)

    # update popupMenu2
    menu = popupMenu2['menu']
    menu.delete(0, 'end')
    for op in operation[i]:
        menu.add_command(label=op, command=tk._setit(tkvar2, op, on_operation_change))
    tkvar2.set('Operation')

    # clear popupMenu3
    popupMenu3['menu'].delete(0, 'end')
    tkvar3.set('Room')

def on_operation_change(op):
    print("Chosen operation", op)

    i = products.index(tkvar.get())
    j = operation[i].index(op)

    # update popupMenu3
    menu = popupMenu3['menu']
    menu.delete(0, 'end')
    for item in room[i][j]:
        menu.add_command(label=item, command=tk._setit(tkvar3, item, on_room_change))
    tkvar3.set('Room')

def on_room_change(room):
    print("Chosen room", room)

popupMenu1 = tk.OptionMenu(canvas, tkvar, *products, command=on_product_change)
popupMenu1.pack()

popupMenu2 = tk.OptionMenu(canvas, tkvar2, [])
popupMenu2.pack()

popupMenu3 = tk.OptionMenu(canvas, tkvar3, [])
popupMenu3.pack()

root.mainloop()
  • Related