Search code examples
pythontkinterargumentsoptionmenu

OptionMenu callback not passing string or variable as expected


I have a simple form that I have built using tkinter. One of my widgets is a text option menu that allows the user to select 1 of 4 corporate or entity types. The widget straight after that requires the corporate or entity registration number

Logically if the user selects "Sole Proprietor", there is no reg number required as Sole Proprietors don't have reg numbers, so if this the case and the user selects "Sole Proprietor", I want the reg number widget to disappear.

So what I do is trace the OptionMenu Variable and if and pass it to the call back as can be seen below:

# Organisation Type (Drop List)
CurrentRowXAlignment += 3
OrgTypeLabel = tk.Label(SetUpWindow, text="Organisation Type:", font=('​Helvetica', 11, 'bold'))
OrgTypeLabel.place(x=ColumnXAlignment1, y=CurrentRowXAlignment, anchor=LabelAnchors)
OrgType = tk.StringVar(SetUpWindow)
OrgType.set(client_data_list[2])
OrgTypeEntry = tk.OptionMenu(SetUpWindow, OrgType, "Private Company (\"(Pty) Ltd\")",
                             "Public Company (\"Limited\")",
                             "Closed Corporation (\"cc\")", "Sole Proprietor")
OrgTypeEntry.place(x=ColumnXAlignment2 - 2, y=CurrentRowXAlignment - 3, anchor=EntryBoxAnchors)
OrgTypeEntry.bind("<Tab>",MovetoNextField)
OrgType.trace("w", lambda *args, org_type=OrgType.get(): ShowRegNumber(org_type, *args))
CurrentRowXAlignment += RowGap

The call back function is as follows:

def ShowRegNumber(org_type, *args):

    if org_type == "Sole Proprietor":
        CoRegNumLabel.forget()
        CoRegNumEntry.forget()
    else:
        pass

For some reason the org-type is not passing - I have tried to debug and it keeps passing '' and therefore is keeps going to the "else" no matter what option on the menu is selected.

Anyone have an idea of what I am doing wrong?


Solution

  • When you use in lambda

     org_type=OrgType.get()
    

    then it gets value OrgType.get() only once - at start - and it assign this value.

    You could use

     lambda *args: ShowRegNumber( OrgType.get(), *args)
    

    but more readable is to use it in function

     def ShowRegNumber(*args):
    
         org_type = OrgType.get()
    

    but even better is to use

    tk.OptionMenu(..., command=ShowRegNumber)
    

    and then you get selected value as the only argument in ShowRegNumber

    def ShowRegNumber(org_type):
    

    Minimal working example

    import tkinter as tk
    
    # --- functions ---
    
    def show_reg_number(selected):
        print(selected)
    
    # --- main ---
    
    setup_window = tk.Tk()
    
    client_data_list = [
        'Private Company ("(Pty) Ltd")',
        'Public Company ("Limited")',
        'Closed Corporation ("cc")', 
        'Sole Proprietor',
    ]
        
    org_type = tk.StringVar(setup_window)
    org_type.set(client_data_list[2])
    
    org_type_entry = tk.OptionMenu(setup_window, org_type, *client_data_list, command=show_reg_number)
    org_type_entry.pack()
        
    setup_window.mainloop()    
    

    BTW:

    I used lower case names for variables and function because of PEP 8 -- Style Guide for Python Code