0

New to python and trying to create an app with customtkinter. The app lets users pick values from different drop-downs and generates codes based on the chosen value.

Updated per comment from Mike-SMT:

import customtkinter as ctk
ctk.set_appearance_mode('light')

# define fonts
general_labels = button_text = ('Segoe UI', 18)
frame_heading = ('Segoe UI Semibold', 20)
small_label = ('Segoe UI', 12)

class FrameSpcl(ctk.CTkFrame): 
    def __init__(self, parent, rownum, colnum, frame_text, attributes_dict):
        super().__init__(parent)

        ctk.CTkLabel(master=self, text=frame_text, font = frame_heading).pack(padx=5, pady=5)
        self.configure(width=200, height=500, corner_radius=10, 
                       bg_color='transparent', fg_color='#d8ebca')
        
        # Create an empty list to store all ComboBox instances 
        combobox_list = []

        for attribute in list(attributes_dict.keys()):
            ctk.CTkLabel(master=self, text='Select '+attribute.replace('_', ' ').lower(), font=small_label, justify='left').pack(padx=10,pady=10)
            combobox_list.append(ctk.CTkComboBox(master=self, values=list(attributes_dict[attribute].keys())).pack(padx=20, pady=(0,20)))
        
        ctk.CTkButton(master=self, text='Generate Code', font=general_labels).pack(padx=20, pady=20) #, command=classFunc)
        code_lab = ctk.CTkLabel(master=self, text='Click to generate Code', font = frame_heading).pack(padx=5, pady=5)

        code_val = ''

        def classFunc():
            attributes = list(attributes_dict.keys())
            for i in range(0,len(combobox_list)):
                code_val += ' '+str(attributes_dict[attributes[i]].get(combobox_list[i].get()))
            print(code_val)
            return(code_val)
        
        # code_lab.configure(text='PN: '+classFunc())

        self.grid(row=rownum, column=colnum, padx=(20,20), pady=(20,20), sticky = 'n')

app = ctk.CTk()
app.geometry('950x700')
app.title('Car Code Generator')

car = dict(
    model = dict(zip(
        ['S', '3', 'X', 'Y'], 
        list(range(0,4))
    )), 
    trim = dict(zip(
        ['Standard', 'Long Range', 'All Wheel Drive', 'Sports'],
        ['RWD', 'RWDLR', 'AWD', 'SPRTS']
    ))
)

sale_terms = dict(
    lease = dict(zip(
        ['5 year', '6 year', '7 year', 'None'],
        ['5YL', '6YL', '7YL', '000']
    )), 
    insurance = dict(zip(
        ['base', '3 year enhanced', '5 year enhanced', 'None'], 
        list(range(0,4))
    )), 
    rewards = dict(zip(
        ['None', 'Bronze', 'Silver', 'Gold', 'Platinum', 'Diamond'], 
        list(range(0,6))
    ))
)

FrameSpcl(parent=app, rownum=0, colnum=0, frame_text='Car Options', attributes_dict=car)

FrameSpcl(parent=app, rownum=0, colnum=1, frame_text='Sale options', attributes_dict=sale_terms)

app.mainloop()

I'm not sure how to update the value for the label when the button is pressed. I tried using configure(text=pn) but it didn't work (commented out in the above code).

The rest of the app appears exactly how I want it to:

enter image description here

2
  • Have you tried to assign each new Cmbobox to a list or dict so you can then call the index/key to get each Cmbobox details? ` You may also need to use a lambda to prevent a issue with the i in your loop from only assigning the last value to all Cmbobox. Commented Jan 17, 2024 at 19:54
  • @Mike-SMT I'm not sure how to assign each new instance to a list. Could you give me an example (fairly new to python here)? The code output looks okay in terms of expected values (I'll update question with the image). Commented Jan 17, 2024 at 21:16

1 Answer 1

1

You have appended results of .pack() to combobox_list which are all None. Also it is better to use instance method instead of nested function.

Below is the modified FrameSpcl class:

class FrameSpcl(ctk.CTkFrame):
    def __init__(self, parent, rownum, colnum, frame_text, attributes_dict):
        super().__init__(parent)
        # save attributs_dict for later use
        self.attributes_dict = attributes_dict

        ctk.CTkLabel(master=self, text=frame_text, font = frame_heading).pack(padx=5, pady=5)
        self.configure(width=200, height=500, corner_radius=10,
                       bg_color='transparent', fg_color='#d8ebca')

        # Create an empty list to store all ComboBox instances
        self.combobox_list = []  ### changed to instance variable

        for attribute in list(attributes_dict.keys()):
            ctk.CTkLabel(master=self, text='Select '+attribute.replace('_', ' ').lower(), font=small_label, justify='left').pack(padx=10,pady=10)
            ### split to two lines
            cb = ctk.CTkComboBox(master=self, values=list(attributes_dict[attribute].keys()))
            cb.pack(padx=20, pady=(0,20))
            # store the combobox to list
            self.combobox_list.append(cb)

        # added command=self.classFunc
        btn = ctk.CTkButton(master=self, text='Generate Code', font=general_labels, command=self.classFunc)
        btn.pack(padx=20, pady=20)
        # changed to self.code_lab
        self.code_lab = ctk.CTkLabel(master=self, text='Click to generate Code', font = frame_heading)
        self.code_lab.pack(padx=5, pady=5)

        self.grid(row=rownum, column=colnum, padx=(20,20), pady=(20,20), sticky = 'n')

    # changed to class method
    def classFunc(self):
        attributes = list(self.attributes_dict.keys())
        code_val = ''
        for i in range(0,len(self.combobox_list)):
            code_val += ' '+str(self.attributes_dict[attributes[i]].get(self.combobox_list[i].get()))
        print(code_val)
        ### update label
        self.code_lab.configure(text=code_val)
        return(code_val)

Updated: added updating label.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks this works! I obviously need to improve my skills in python :) Could you also suggest a way to include an optional text entry box that's added only if a variable is passed to the class along with position (e.g. after the 3rd combobox). The value entered in this widget would be added as is to the code in the specified position.
It is not that hard to do what you want.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.