Search code examples
pythontkinterdependenciesdropdownoptionmenu

OptionMenu's dependency on other OptionMenus is not working after the Reset Button (which resets the selections made on the OptionMenus) is clicked


I am trying to create a UNIT CONVERTER which is a GUI application in Python using Tkinter. I have created one main OptionMenu and two other OptionMenus. These other two OptionMenus are dependent on the main OptionMenu i.e.upon selecting a value from the main OptionMenu, the list of values in the other two OptionMenus changes. I have created two buttons "Convert" and "Reset". In the Reset Button, I am trying to reset the selections on all three OptionMenus.

Source Code

import tkinter as tk
from tkinter import messagebox
from math import * 


root = tk.Tk()
root.title("Unit Converter")
root.geometry("600x400")

# A function for updating the dropdown lists upon selecting the operation.
def updateSubLists(self):
    y.set('')
    z.set('')
    subUnitListFrom['menu'].delete(0,'end')
    subUnitListTo['menu'].delete(0,'end')
     
    for item in list(listOfUnits.get(x.get())):
        subUnitListFrom['menu'].add_command(label=item,command=tk._setit(y,item))
        subUnitListTo['menu'].add_command(label=item,command=tk._setit(z,item))
    
    y.set(list(listOfUnits.get(x.get()))[0])
    z.set(list(listOfUnits.get(x.get()))[0])

# A callback function to validate if the data entered is only digit or not.
def validateUserInput(input):
    """This method validates the data entered by the User to check if the entered data is a number or not."""
    if input.isdigit() == True:
        return True
    elif input == "":
        return True
    else:
        messagebox.showinfo("Information","Only number is allowed")
        return False
  

# A function for resetting the entries selected.
def resetEntries():
    """ This method helps in resetting the entries given as a input or selected by the User"""
    x.set("")
    unitList["menu"].delete(0,'end')
    for item in list(listOfUnits.keys()):
        unitList['menu'].add_command(label=item,command=tk._setit(x,item))
    x.set(list(listOfUnits.keys())[0])
    
    #updateSubLists('')
    y.set('')
    z.set('')
    subUnitListFrom['menu'].delete(0,'end')
    subUnitListTo['menu'].delete(0,'end')
     
    for item in list(listOfUnits.get(x.get())):
        subUnitListFrom['menu'].add_command(label=item,command=tk._setit(y,item))
        subUnitListTo['menu'].add_command(label=item,command=tk._setit(z,item))
    
    y.set(list(listOfUnits.get(x.get()))[0])
    z.set(list(listOfUnits.get(x.get()))[0])


# Lists and Sub-lists creation 
#listOfUnits = ['Area','Energy','Frequency','Length','Mass','Pressure','Speed','Temperature',
               #'Time','Volume']

listOfUnits = {"Area":['Square Kilometer','Squatre Meter','Square Mile','Square Yard','Square Foot','Square Inch','Hectare','Acre'],
            "Energy":['Joule','Kilo Joule','Gram Calorie','Kilo Calorie'],
            "Frequency":['Hertz','Kilohertz','Megahertz','Kilohertz'],
            "Length":['Kilometer','Meter','Centimeter','Millimeter','Micrometer','Nanometer','Mile','Yard','Foot','Inch'],
            "Mass":['Tonne','Kilogram','Microgram','Milligram','Gram','Pound','Ounce'],
            "Pressure":['Bar','Pascal','Pound per square inch','Standard atmosphere','Torr'],
            "Speed":['Miles per hour','Meter per second','Foot per second','Kilometer per hour','Knot'],
            "Temperature":['Celcius','Farhenheit','Kelvin'],
            "Time":['Nanosecond','Microsecond','Millisecond','Second','Minute','Hour','Day','Week','Month','Calender Year','Decade','Century'],
            "Volume":['Litre','Millilitre','Imperial Gallon','Imperial Pint']
           }

# label text for header title
headerLbl = tk.Label(root,text="UNIT CONVERTER",fg="black",bg="light grey",font = ("Times New Roman", 30,"bold","italic","underline"))
headerLbl.grid(row = 0,column = 1,columnspan = 3)

# Label text for conversion tye selection 
lbl1 = tk.Label(root,text="Type of Conversion:")
lbl1.grid(row = 1,column = 0,padx=20,pady=20)


# OptionMenu creation for the list of Units to select
global x 
x = tk.StringVar()
x.set(list(listOfUnits.keys())[0])
unitList = tk.OptionMenu(root,x,*listOfUnits.keys(),command=updateSubLists)
unitList.grid(row = 1,column = 1,padx=20,pady=40)

# Label text for conversion type selection 
lbl2 = tk.Label(root,text="From")
lbl2.grid(row = 2,column = 0)


# OptionMenu creation for the list of Sub Units to select.
global y 
y = tk.StringVar()
y.set(list(listOfUnits.get(x.get()))[0])
subUnitListFrom = tk.OptionMenu(root,y,*listOfUnits.get(x.get()))
subUnitListFrom.grid(row=2,column=1,padx=20,pady=40)


# Entry widget for From label
fromEntry = tk.Entry(root,width=20)
valid_info = root.register(validateUserInput)   # register the function for the validation
fromEntry.config(validate="key",validatecommand=(valid_info,'%P'))  # Adding the properties for validation elements
fromEntry.grid(row=2,column=2)

# Label text for conversion type selection 
lbl3 = tk.Label(root,text="To")
lbl3.grid(row = 3,column = 0)

# OptionMenu creation for the list of Sub Units to select.
global z 
z = tk.StringVar()
z.set(list(listOfUnits.get(x.get()))[0])
subUnitListTo = tk.OptionMenu(root,z,*listOfUnits.get(x.get()))
subUnitListTo.grid(row=3,column=1)

# Entry widget for From label
ToEntry = tk.Entry(root,width=20,state="readonly")
ToEntry.grid(row=3,column=2)

# Logic for the convert button
convert_button = tk.Button(root,text="CONVERT",fg="black",bg ="yellow",font=("Times New Roman",12,"bold"))
convert_button.grid(row=4,column=1,padx=20,pady=40)

# Logic for the reset button
reset_button = tk.Button(root,text="RESET",fg="black",bg="yellow",font=("Times New Roman",12,"bold"),command=resetEntries)
reset_button.grid(row=4,column=2,padx=20,pady=40)

root.mainloop()

Problem Statement: When clicked on Reset, logic works successfully but when I again select a new value in the main OptionMenu, the corresponding list of values are not reflecting in the other two OptionMenus. I am not able to understand "after I click the Reset Button , why my other two dropdowns are not reflecting the corresponding values when I change the value of the main OptionMenu".


Solution

  • You forget to pass updateSubLists as the third argument of tk._setit(...) inside resetEntries():

    def resetEntries():
        """ This method helps in resetting the entries given as a input or selected by the User"""
        x.set("")
        unitList["menu"].delete(0,'end')
        for item in list(listOfUnits.keys()):
            unitList['menu'].add_command(label=item,command=tk._setit(x,item,updateSubLists))
    
        ...