Python Forum

Full Version: CTkComboBox - not working
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
Hi everyone
I am using customtkinter to make some comboboxes

Basically I have a list of Groups, which have their own corresponding models and buckets available

see the dictionaries below please

models_data = {
"Caterpillar LHD models": {
"R1300G": ["DB 3.4", "DB 2.8", "DB 2.5", "DB 3.1"],
"R1600H": ["DB 5.9", "DB 4.8", "DB 4.2", "DB 5.6"],
"R1700": ["DB 5.7", "DB 6.1", "DB 6.6", "DB 7.5", "DB 8"],
"R1700XE": ["DB 5.7", "DB 6.1", "DB 6.6", "DB 7.5"],
"R1700G": ["DB 4.6", "DB 5", "DB 6.6", "DB 5.7", "DB 7.3", "DB 8.8"],
"R2900G": ["DB 8.9", "DB 7.2", "DB 6.3", "DB 8.3"],
"R2900": ["DB 6.3", "DB 7.2", "DB 8.3", "DB 8.9"],
"R2900XE": ["DB 7.4", "DB 8.6", "DB 9.2", "DB 9.8"],
"R3000H": ["DB 10.5", "DB 8.9", "DB 9.5"]
},
"Sandvik LHD models": {
"SANDVIK LH517i": ["DB 7", "DB 7.6", "DB 8.6", "DB 9.1", "DB 8.4"],
"SANDVIK LH621i": ["DB 8.0", "DB 9.0", "DB 10.7", "DB 11.2"],
"SANDVIK LH515i": ["DB 6.3", "DB 6.8", "DB 7.5"],
"SANDVIK LH514": ["DB 6.2", "DB 7", "DB 5.4"],
"Toro™ LH625iE": ["DB 10"],
"Sandvik LH514E": ["DB 4.6", "DB 5", "DB 5.4", "DB 6.2", "DB 7"],
"Toro™ LH514BE": ["DB 4.6", "DB 5", "DB 5.4", "DB 6.2", "DB 7", "DB 7.5"],
"Sandvik LH409E": ["DB 3.8", "DB 4.3", "DB 4.6"]
},
"Epiroc LHD models": {
"Epiroc ST14 SG": ["DB 4.7", "DB 5", "DB 5.4", "DB 5.8", "DB 6.4", "DB 7.0", "DB 7.8"],
"Epiroc ST18 SG": ["DB 9.7", "DB 8.8", "DB 7.9", "DB 7.3", "DB 6.7", "DB 6.3"],
"Epiroc ST14": ["DB 4.7", "DB 5", "DB 5.4", "DB 5.8", "DB 6.4", "DB 7.0", "DB 7.8"],
"Epiroc ST18 S": ["DB 9.7", "DB 8.8", "DB 7.9", "DB 7.3", "DB 6.7", "DB 6.3"]
},
"Komatsu LHD models": {
"WX18H": ["DB 8.2", "DB 9.2", "DB 10", "DB 11.2"],
"WX22H": ["DB 10", "DB 11", "DB 12.2", "DB 13.8"]
}

So I have setup some definitions as such

def on_group_selected(col):
selected_group = group_vars[col].get()
model_dropdowns[col]['values'] = list(models_data[selected_group].keys())
model_vars[col].set("")
buckets_dropdowns[col]['values'] = []

def on_model_selected(col):
selected_group = group_vars[col].get()
selected_model = model_vars[col].get()
if selected_model != "":
bucket_values = models_data[selected_group][selected_model]
buckets_dropdowns[col]['values'] = bucket_values


I have setup the labels as such
# Group dropdown
group_var = ctk.StringVar()
group_var.set(list(models_data.keys())[col])
group_vars.append(group_var)
group_dropdown = ctk.CTkComboBox(column_frame, variable=group_var, values=list(models_data.keys()),font=("Univers-Light-Normal", 10), width=200, justify="center", command=on_model_selected)
group_dropdown.bind("<<ComboboxSelected>>", lambda event, col=col: on_group_selected(col))
group_dropdown.pack(pady=10)

# Model dropdown
model_var = ctk.StringVar()
model_var.set("Select Model")
model_vars.append(model_var)
model_dropdown = ctk.CTkComboBox(column_frame, variable=model_var, values=[], font=("Univers-Light-Normal", 10), width=200)
model_dropdown.bind("<<ComboboxSelected>>", lambda event, col=col: on_model_selected(col))
model_dropdown.pack(pady=10)
model_dropdowns.append(model_dropdown)

# Buckets dropdown
buckets_var = ctk.StringVar()
buckets_var.set("")
buckets_dropdown = ctk.CTkComboBox(column_frame, variable=buckets_var, values=[],font=("Univers-Light-Normal", 10) ,width=80)
buckets_dropdown.pack(pady=10)
buckets_dropdowns.append(buckets_dropdown)


My Group drop down works, the model dropdown and buckets don't work, essentially no list to select from
Can someone please help me out?

Thank you!
Please use bb tags when posting. It helps with the formatting.
[quote="Sedos101" pid='172259' dateline='1693114093']
Hi everyone
I am using customtkinter to make some comboboxes

Basically I have a list of Groups, which have their own corresponding models and buckets available

see the dictionaries below please

models_data = {
    "Caterpillar LHD models": {
        "R1300G": ["DB 3.4", "DB 2.8", "DB 2.5", "DB 3.1"],
        "R1600H": ["DB 5.9", "DB 4.8", "DB 4.2", "DB 5.6"],
        "R1700": ["DB 5.7", "DB 6.1", "DB 6.6", "DB 7.5", "DB 8"],
        "R1700XE": ["DB 5.7", "DB 6.1", "DB 6.6", "DB 7.5"],
        "R1700G": ["DB 4.6", "DB 5", "DB 6.6", "DB 5.7", "DB 7.3", "DB 8.8"],
        "R2900G": ["DB 8.9", "DB 7.2", "DB 6.3", "DB 8.3"],
        "R2900": ["DB 6.3", "DB 7.2", "DB 8.3", "DB 8.9"],
        "R2900XE": ["DB 7.4", "DB 8.6", "DB 9.2", "DB 9.8"],
        "R3000H": ["DB 10.5", "DB 8.9", "DB 9.5"]
    },
    "Sandvik LHD models": {
        "SANDVIK LH517i": ["DB 7", "DB 7.6", "DB 8.6", "DB 9.1", "DB 8.4"],
        "SANDVIK LH621i": ["DB 8.0", "DB 9.0", "DB 10.7", "DB 11.2"],
        "SANDVIK LH515i": ["DB 6.3", "DB 6.8", "DB 7.5"],
        "SANDVIK LH514": ["DB 6.2", "DB 7", "DB 5.4"],
        "Toro™ LH625iE": ["DB 10"],
        "Sandvik LH514E": ["DB 4.6", "DB 5", "DB 5.4", "DB 6.2", "DB 7"],
        "Toro™ LH514BE": ["DB 4.6", "DB 5", "DB 5.4", "DB 6.2", "DB 7", "DB 7.5"],
        "Sandvik LH409E": ["DB 3.8", "DB 4.3", "DB 4.6"]
    },
    "Epiroc LHD models": {
        "Epiroc ST14 SG": ["DB 4.7", "DB 5", "DB 5.4", "DB 5.8", "DB 6.4", "DB 7.0", "DB 7.8"],
        "Epiroc ST18 SG": ["DB 9.7", "DB 8.8", "DB 7.9", "DB 7.3", "DB 6.7", "DB 6.3"],
        "Epiroc ST14": ["DB 4.7", "DB 5", "DB 5.4", "DB 5.8", "DB 6.4", "DB 7.0", "DB 7.8"],
        "Epiroc ST18 S": ["DB 9.7", "DB 8.8", "DB 7.9", "DB 7.3", "DB 6.7", "DB 6.3"]
    },
    "Komatsu LHD models": {
        "WX18H": ["DB 8.2", "DB 9.2", "DB 10", "DB 11.2"],
        "WX22H": ["DB 10", "DB 11", "DB 12.2", "DB 13.8"]
    }
So I have setup some definitions as such

def on_group_selected(col):
    selected_group = group_vars[col].get()
    model_dropdowns[col]['values'] = list(models_data[selected_group].keys())
    model_vars[col].set("")
    buckets_dropdowns[col]['values'] = []

def on_model_selected(col):
    selected_group = group_vars[col].get()
    selected_model = model_vars[col].get()
    if selected_model != "":
        bucket_values = models_data[selected_group][selected_model]
        buckets_dropdowns[col]['values'] = bucket_values
I have setup the labels as such
    # Group dropdown
    group_var = ctk.StringVar()
    group_var.set(list(models_data.keys())[col])
    group_vars.append(group_var)
    group_dropdown = ctk.CTkComboBox(column_frame, variable=group_var, values=list(models_data.keys()),font=("Univers-Light-Normal", 10), width=200, justify="center", command=on_model_selected)
    group_dropdown.bind("<<ComboboxSelected>>", lambda event, col=col: on_group_selected(col))
    group_dropdown.pack(pady=10)

    # Model dropdown
    model_var = ctk.StringVar()
    model_var.set("Select Model")
    model_vars.append(model_var)
    model_dropdown = ctk.CTkComboBox(column_frame, variable=model_var, values=[], font=("Univers-Light-Normal", 10), width=200)
    model_dropdown.bind("<<ComboboxSelected>>", lambda event, col=col: on_model_selected(col))
    model_dropdown.pack(pady=10)
    model_dropdowns.append(model_dropdown)

    # Buckets dropdown
    buckets_var = ctk.StringVar()
    buckets_var.set("")
    buckets_dropdown = ctk.CTkComboBox(column_frame, variable=buckets_var, values=[],font=("Univers-Light-Normal", 10)  ,width=80)
    buckets_dropdown.pack(pady=10)
    buckets_dropdowns.append(buckets_dropdown)
My Group drop down works, the model dropdown and buckets don't work, essentially no list to select from
Can someone please help me out?

Thank you!
(Aug-27-2023, 05:30 AM)menator01 Wrote: [ -> ]Please use bb tags when posting. It helps with the formatting.

Hi I have updated, any chance you can help please?

Thanks you
You need to update the model list when the group selection changes. Same goes with updating the bucket list when you select a model. You tried to do this, but didn't succeed, primarily because of this:
group_dropdown.bind("<<ComboboxSelected>>", lambda event, col=col: on_group_selected(col))
This sets up your software to call on_group_selected when the user makes a selection. Sounds good, but it is not what you want. What you really want is to call on_group_selected whenever the selection is set, either by clicking on a item, or by setting the string variable associated with the combo box. You want to use StringVar.trace():
import tkinter as tk
import tkinter.ttk as ttk

models_data = {
    "Caterpillar LHD models": {
        "R1300G": ["DB 3.4", "DB 2.8", "DB 2.5", "DB 3.1"],
        "R1600H": ["DB 5.9", "DB 4.8", "DB 4.2", "DB 5.6"],
        "R1700": ["DB 5.7", "DB 6.1", "DB 6.6", "DB 7.5", "DB 8"],
        "R1700XE": ["DB 5.7", "DB 6.1", "DB 6.6", "DB 7.5"],
        "R1700G": ["DB 4.6", "DB 5", "DB 6.6", "DB 5.7", "DB 7.3", "DB 8.8"],
        "R2900G": ["DB 8.9", "DB 7.2", "DB 6.3", "DB 8.3"],
        "R2900": ["DB 6.3", "DB 7.2", "DB 8.3", "DB 8.9"],
        "R2900XE": ["DB 7.4", "DB 8.6", "DB 9.2", "DB 9.8"],
        "R3000H": ["DB 10.5", "DB 8.9", "DB 9.5"]
    },
    "Sandvik LHD models": {
        "SANDVIK LH517i": ["DB 7", "DB 7.6", "DB 8.6", "DB 9.1", "DB 8.4"],
        "SANDVIK LH621i": ["DB 8.0", "DB 9.0", "DB 10.7", "DB 11.2"],
        "SANDVIK LH515i": ["DB 6.3", "DB 6.8", "DB 7.5"],
        "SANDVIK LH514": ["DB 6.2", "DB 7", "DB 5.4"],
        "Toro™ LH625iE": ["DB 10"],
        "Sandvik LH514E": ["DB 4.6", "DB 5", "DB 5.4", "DB 6.2", "DB 7"],
        "Toro™ LH514BE": ["DB 4.6", "DB 5", "DB 5.4", "DB 6.2", "DB 7", "DB 7.5"],
        "Sandvik LH409E": ["DB 3.8", "DB 4.3", "DB 4.6"]
    },
    "Epiroc LHD models": {
        "Epiroc ST14 SG": ["DB 4.7", "DB 5", "DB 5.4", "DB 5.8", "DB 6.4", "DB 7.0", "DB 7.8"],
        "Epiroc ST18 SG": ["DB 9.7", "DB 8.8", "DB 7.9", "DB 7.3", "DB 6.7", "DB 6.3"],
        "Epiroc ST14": ["DB 4.7", "DB 5", "DB 5.4", "DB 5.8", "DB 6.4", "DB 7.0", "DB 7.8"],
        "Epiroc ST18 S": ["DB 9.7", "DB 8.8", "DB 7.9", "DB 7.3", "DB 6.7", "DB 6.3"]
    },
    "Komatsu LHD models": {
        "WX18H": ["DB 8.2", "DB 9.2", "DB 10", "DB 11.2"],
        "WX22H": ["DB 10", "DB 11", "DB 12.2", "DB 13.8"]
    }
}


class ComboBox(ttk.Combobox):
    """A convenient Combobox."""
    def __init__(self, *args, command=None, **kwargs):
        self.value = tk.StringVar()
        self.value.trace("w", command)
        super().__init__(
            *args, textvariable=self.value, **kwargs
        )

    def set_values(self, values):
        """Set values in list."""
        self["values"] = values
        if values:
            self.set(values[0])

    def get(self):
        """Return value."""
        return self.value.get()

    def set(self, value):
        """Set value."""
        self.value.set(value)


class Column(tk.Frame):
    """Controls for selecting a loader"""
    def __init__(self, *args, command=None, width=30, **kwargs):
        super().__init__(*args, **kwargs)
        self.command = command
        self.group = ComboBox(
            self, values=list(models_data), command=self._group_cb, width=width
        )
        self.model = ComboBox(self, command=self._model_cb, width=width)
        self.bucket = ComboBox(self, command=self._bucket_cb, width=width)
        self.group.pack(pady=10)
        self.model.pack(pady=10)
        self.bucket.pack(pady=10)

    def _group_cb(self, *_):
        """Group selection changed.  Update model dropdown."""
        self.model.set_values(list(models_data[self.group.get()]))

    def _model_cb(self, *_):
        """Model selection changed.  Update bucket dropdown."""
        self.bucket.set_values(list(models_data[self.group.get()][self.model.get()]))

    def _bucket_cb(self, *_):
        """Bucket selection changed.  Execute selection callback command."""
        if self.command:
            self.command(self.selection())

    def selection(self):
        """Return selected manufacturer, model, bucket."""
        return self.group.get(), self.model.get(), self.bucket.get()


class Window(tk.Tk):
    def __init__(self):
        super().__init__()
        width = max(len(key) for key in models_data)
        for group in models_data:
            column = Column(self, command=print, width=width)
            column.pack(side=tk.LEFT, padx=10, pady=10)
            column.group.set(group)


Window().mainloop()
(Aug-27-2023, 11:38 AM)deanhystad Wrote: [ -> ]You need to update the model list when the group selection changes. Same goes with updating the bucket list when you select a model.

Can you please tell show me how to do that?
See above.

And please post runnable examples that demonstrate the problem.
(Aug-27-2023, 02:04 PM)deanhystad Wrote: [ -> ]See above.

And please post runnable examples that demonstrate the problem.

THANK YOU SOO MUCH!!
Hi I just realised you changed the code from ctk.CTkCombobox to the regular tk.Combobox
are you able to do this in the ctk.CTkCombobox instead please?


(Aug-27-2023, 11:38 AM)deanhystad Wrote: [ -> ]You need to update the model list when the group selection changes. Same goes with updating the bucket list when you select a model. You tried to do this, but didn't succeed, primarily because of this:
group_dropdown.bind("<<ComboboxSelected>>", lambda event, col=col: on_group_selected(col))
This sets up your software to call on_group_selected when the user makes a selection. Sounds good, but it is not what you want. What you really want is to call on_group_selected whenever the selection is set, either by clicking on a item, or by setting the string variable associated with the combo box. You want to use StringVar.trace():
import tkinter as tk
import tkinter.ttk as ttk

models_data = {
    "Caterpillar LHD models": {
        "R1300G": ["DB 3.4", "DB 2.8", "DB 2.5", "DB 3.1"],
        "R1600H": ["DB 5.9", "DB 4.8", "DB 4.2", "DB 5.6"],
        "R1700": ["DB 5.7", "DB 6.1", "DB 6.6", "DB 7.5", "DB 8"],
        "R1700XE": ["DB 5.7", "DB 6.1", "DB 6.6", "DB 7.5"],
        "R1700G": ["DB 4.6", "DB 5", "DB 6.6", "DB 5.7", "DB 7.3", "DB 8.8"],
        "R2900G": ["DB 8.9", "DB 7.2", "DB 6.3", "DB 8.3"],
        "R2900": ["DB 6.3", "DB 7.2", "DB 8.3", "DB 8.9"],
        "R2900XE": ["DB 7.4", "DB 8.6", "DB 9.2", "DB 9.8"],
        "R3000H": ["DB 10.5", "DB 8.9", "DB 9.5"]
    },
    "Sandvik LHD models": {
        "SANDVIK LH517i": ["DB 7", "DB 7.6", "DB 8.6", "DB 9.1", "DB 8.4"],
        "SANDVIK LH621i": ["DB 8.0", "DB 9.0", "DB 10.7", "DB 11.2"],
        "SANDVIK LH515i": ["DB 6.3", "DB 6.8", "DB 7.5"],
        "SANDVIK LH514": ["DB 6.2", "DB 7", "DB 5.4"],
        "Toro™ LH625iE": ["DB 10"],
        "Sandvik LH514E": ["DB 4.6", "DB 5", "DB 5.4", "DB 6.2", "DB 7"],
        "Toro™ LH514BE": ["DB 4.6", "DB 5", "DB 5.4", "DB 6.2", "DB 7", "DB 7.5"],
        "Sandvik LH409E": ["DB 3.8", "DB 4.3", "DB 4.6"]
    },
    "Epiroc LHD models": {
        "Epiroc ST14 SG": ["DB 4.7", "DB 5", "DB 5.4", "DB 5.8", "DB 6.4", "DB 7.0", "DB 7.8"],
        "Epiroc ST18 SG": ["DB 9.7", "DB 8.8", "DB 7.9", "DB 7.3", "DB 6.7", "DB 6.3"],
        "Epiroc ST14": ["DB 4.7", "DB 5", "DB 5.4", "DB 5.8", "DB 6.4", "DB 7.0", "DB 7.8"],
        "Epiroc ST18 S": ["DB 9.7", "DB 8.8", "DB 7.9", "DB 7.3", "DB 6.7", "DB 6.3"]
    },
    "Komatsu LHD models": {
        "WX18H": ["DB 8.2", "DB 9.2", "DB 10", "DB 11.2"],
        "WX22H": ["DB 10", "DB 11", "DB 12.2", "DB 13.8"]
    }
}


class ComboBox(ttk.Combobox):
    """A convenient Combobox."""
    def __init__(self, *args, command=None, **kwargs):
        self.value = tk.StringVar()
        self.value.trace("w", command)
        super().__init__(
            *args, textvariable=self.value, **kwargs
        )

    def set_values(self, values):
        """Set values in list."""
        self["values"] = values
        if values:
            self.set(values[0])

    def get(self):
        """Return value."""
        return self.value.get()

    def set(self, value):
        """Set value."""
        self.value.set(value)


class Column(tk.Frame):
    """Controls for selecting a loader"""
    def __init__(self, *args, command=None, width=30, **kwargs):
        super().__init__(*args, **kwargs)
        self.command = command
        self.group = ComboBox(
            self, values=list(models_data), command=self._group_cb, width=width
        )
        self.model = ComboBox(self, command=self._model_cb, width=width)
        self.bucket = ComboBox(self, command=self._bucket_cb, width=width)
        self.group.pack(pady=10)
        self.model.pack(pady=10)
        self.bucket.pack(pady=10)

    def _group_cb(self, *_):
        """Group selection changed.  Update model dropdown."""
        self.model.set_values(list(models_data[self.group.get()]))

    def _model_cb(self, *_):
        """Model selection changed.  Update bucket dropdown."""
        self.bucket.set_values(list(models_data[self.group.get()][self.model.get()]))

    def _bucket_cb(self, *_):
        """Bucket selection changed.  Execute selection callback command."""
        if self.command:
            self.command(self.selection())

    def selection(self):
        """Return selected manufacturer, model, bucket."""
        return self.group.get(), self.model.get(), self.bucket.get()


class Window(tk.Tk):
    def __init__(self):
        super().__init__()
        width = max(len(key) for key in models_data)
        for group in models_data:
            column = Column(self, command=print, width=width)
            column.pack(side=tk.LEFT, padx=10, pady=10)
            column.group.set(group)


Window().mainloop()
Yes, YOU could do this with CTk combo boxes too. Should be very easy.
Pages: 1 2