Search code examples
pythonstringdictionarytkintercombobox

How to make the text of a Label change automatically?


I am having issues with updating ttk.Label(frame, text=value).grid(column=1, row=2) automatically when a new Combobox option is selected. I know it has something to do with my handler function, but for the life of me, I haven't been able to figure it out.

import tkinter as tk
from tkinter import ttk
from tkinter import *
from time import *

vegetable_needs = {
    'Tomato': {'ph': '6', 'moisture': '60', 'humidity': '70'},
    'Bell pepper': {'ph': '9', 'moisture': '61', 'humidity': '71'},
    'Cucumber': {'ph': '2', 'moisture': '62', 'humidity': '72'},
    'Broccoli': {'ph': '4', 'moisture': '63', 'humidity': '73'},
    'Green Bean': {'ph': '1', 'moisture': '64', 'humidity': '74'},
    'Zucchini': {'ph': '5', 'moisture': '65', 'humidity': '75'},
    'Sweet potatoe': {'ph': '0', 'moisture': '66', 'humidity': '76'}
}

#Create Frame
def create_input_frame(container):
    #declare string variables
    vegetable = tk.StringVar()

    frame = tk.Frame(container, borderwidth=1, relief=RIDGE, padx=15, pady=10)
    
    options = ttk.Combobox(frame, width = 20, textvariable = vegetable)
    #list of veggies
    options['values'] = (
    "Tomato",
    "Bell pepper",
    "Cucumber",
    "Broccoli",
    "Green Bean",
    "Zucchini",
    "Sweet potatoe"
    )
    options['state'] = 'readonly'

    ttk.Label(frame, text = "Select a veggie: ", font = ("Times New Roman", 10)).grid(column=0, row=0, padx=5, pady=0)
    options.grid(column = 1, row = 0)
    options.current()
    

    def handler(event):
        current = options.current()
        if current != -1:
            ph_level = vegetable_needs[vegetable.get()]['ph']
            value = ph_level
            print(value)
    
    
    options.bind('<<ComboboxSelected>>', handler)
    
    ttk.Label(frame, text=value).grid(column=1, row=2)
    ttk.Label(frame, text='PH Level').grid(column=0, row=2)
  
    return frame

#Create the main window
def create_main_window():
    root = tk.Tk()
    root.title('Growing Veggies')
    root.attributes('-toolwindow', False)
    r1=0
    r2=0
    r3=0
    
    #Create zones 1-5 row 0
    if number_of_zones >= 1 and number_of_zones <= 5:
        for r1 in range(number_of_zones):
            input_frame = create_input_frame(root)
            input_frame.grid(column=r1, row=0)
            r1+=1
    #Create zones 6-10 rows 0-1
    elif number_of_zones > 5 and number_of_zones <=10:
        for r1 in range(5):
            input_frame = create_input_frame(root)
            input_frame.grid(column=r1, row=0)
            r1+=1
        for r2 in range(number_of_zones - 5):
            input_frame = create_input_frame(root)
            input_frame.grid(column=r2, row=1)
            r2+=1
    #Create zones 11-15 rows 0-2
    elif number_of_zones > 10 and number_of_zones <=15:
        for r1 in range(5):
            input_frame = create_input_frame(root)
            input_frame.grid(column=r1, row=0)
            r1+=1
        for r2 in range(5):
            input_frame = create_input_frame(root)
            input_frame.grid(column=r2, row=1)
            r2+=1
        for r2 in range(number_of_zones - 10):
            input_frame = create_input_frame(root)
            input_frame.grid(column=r2, row=2)
            r3+=1

    #Output an error
    else:
        root.title('ERROR')
        ttk.Label(root, text = "Please enter a valid number between 1 and 15").grid(column=1, row=1, padx=15, pady=5)
        ttk.Button(root, text = "Acknowledge", command=quit).grid(column=1, row=2, padx=5, pady=5)
    
    root.mainloop()

if __name__ == "__main__":

    value = "?"
    number_of_zones = int(input("How many zones should be made? "))
    create_main_window()
'''

Solution

  • You need to create variables to reference your labels by. Also, you need to update them when the PH is changed. Here is what the code should look like, with changes marked with ### EDITED LINE and ### ADDED LINE:

    import tkinter as tk
    from tkinter import ttk
    from tkinter.constants import *
    
    vegetable_needs = {
        'Tomato': {'ph': '6', 'moisture': '60', 'humidity': '70'},
        'Bell pepper': {'ph': '9', 'moisture': '61', 'humidity': '71'},
        'Cucumber': {'ph': '2', 'moisture': '62', 'humidity': '72'},
        'Broccoli': {'ph': '4', 'moisture': '63', 'humidity': '73'},
        'Green Bean': {'ph': '1', 'moisture': '64', 'humidity': '74'},
        'Zucchini': {'ph': '5', 'moisture': '65', 'humidity': '75'},
        'Sweet potatoe': {'ph': '0', 'moisture': '66', 'humidity': '76'}
    }
    
    #Create Frame
    def create_input_frame(container):
        #declare string variables
        vegetable = tk.StringVar()
    
        frame = tk.Frame(container, borderwidth=1, relief=RIDGE, padx=15, pady=10)
        
        options = ttk.Combobox(frame, width = 20, textvariable = vegetable)
        #list of veggies
        options['values'] = (
        "Tomato",
        "Bell pepper",
        "Cucumber",
        "Broccoli",
        "Green Bean",
        "Zucchini",
        "Sweet potatoe"
        )
        options['state'] = 'readonly'
    
        veggie_label = ttk.Label(frame, text = "Select a veggie: ", font = ("Times New Roman", 10)) ### EDITED LINE
        veggie_label.grid(column=0, row=0, padx=5, pady=0) ### ADDED LINE
        options.grid(column = 1, row = 0)
        options.current()
        
    
        def handler(event):
            current = options.current()
            if current != -1:
                ph_level = vegetable_needs[vegetable.get()]['ph']
                value = ph_level
                value_label.config(text=value) ### ADDED LINE
                print(value)
        
        
        options.bind('<<ComboboxSelected>>', handler)
        
        value_label = ttk.Label(frame, text=value) ### EDITED LINE
        value_label.grid(column=1, row=2) ### ADDED LINE
        ph_label = ttk.Label(frame, text='PH Level') ### EDITED LINE
        ph_label.grid(column=0, row=2) ### ADDED LINE
        
        return frame
    
    #Create the main window
    def create_main_window():
        root = tk.Tk()
        root.title('Growing Veggies')
        # root.attributes('-toolwindow', False)
        r1=0
        r2=0
        r3=0
        
        #Create zones 1-5 row 0
        if number_of_zones >= 1 and number_of_zones <= 5:
            for r1 in range(number_of_zones):
                input_frame = create_input_frame(root)
                input_frame.grid(column=r1, row=0)
                r1+=1
        #Create zones 6-10 rows 0-1
        elif number_of_zones > 5 and number_of_zones <=10:
            for r1 in range(5):
                input_frame = create_input_frame(root)
                input_frame.grid(column=r1, row=0)
                r1+=1
            for r2 in range(number_of_zones - 5):
                input_frame = create_input_frame(root)
                input_frame.grid(column=r2, row=1)
                r2+=1
        #Create zones 11-15 rows 0-2
        elif number_of_zones > 10 and number_of_zones <=15:
            for r1 in range(5):
                input_frame = create_input_frame(root)
                input_frame.grid(column=r1, row=0)
                r1+=1
            for r2 in range(5):
                input_frame = create_input_frame(root)
                input_frame.grid(column=r2, row=1)
                r2+=1
            for r2 in range(number_of_zones - 10):
                input_frame = create_input_frame(root)
                input_frame.grid(column=r2, row=2)
                r3+=1
    
        #Output an error
        else:
            root.title('ERROR')
            error_label = ttk.Label(root, text = "Please enter a valid number between 1 and 15")
            error_label.grid(column=1, row=1, padx=15, pady=5)
            ttk.Button(root, text = "Acknowledge", command=quit).grid(column=1, row=2, padx=5, pady=5)
        
        root.mainloop()
    
    if __name__ == "__main__":
    
        value = "?"
        number_of_zones = int(input("How many zones should be made? "))
        create_main_window()
    

    Notice I define the labels as variables: value_label, ph_label, and error_label. This enables the labels to be referenced throughout the program. Also notice how in the handler function, I call value_label.config(text=value). This sets the value_label's text to the PH level.