0

I want to have 2 multiple selection combobox returning/showing the values of the list. My code looks like that:

data = [[],[]]
nom = [[],[]]
data[0] = [['01_Flat', '02_Curv', '03_RX', '04_RY', '05_RZ', '06_Fsyr', '07_AI']]
data[1] = [['Manual', 'Laser', 'Gamma', 'Proto']]
nom[0] = ['Part']
nom[1] = ['Cutting']


import tkinter as tk
from tkinter import ttk

class Combo(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        menubutton = tk.Menubutton(self, text=nom[k][i], 
                                    indicatoron=True, borderwidth=1, relief="raised")
        menu = tk.Menu(menubutton, tearoff=False)
        menubutton.configure(menu=menu)
        menubutton.pack(padx=10, pady=10)

        self.choices = {}
        for choice in (data[k][i]):
            self.choices[choice] = tk.IntVar(value=0)
            # print(self.choices[choice].get())
            #print(self.choices.get())
            menu.add_checkbutton(label=choice, variable=self.choices[choice], 
                                  onvalue=1, offvalue=0,command=self.show)
    def show(self):
        # global selec
        value = []
        for choice in (data[k][i]):
            value.append(self.choices[choice].get())
        print(value)   
        # selec = value
        return value

root = tk.Tk()

canva = tk.Canvas(root, width = 530,height = 500)
canva.pack(fill = "both", expand = True)

i=0 
k = 0

a = Combo(root)
a = canva.create_window(125,50,anchor = "nw",window = a)

i = 0
k = 1

pos = Combo(root)
pos = canva.create_window(225,50,anchor = "nw",window = pos)

root.mainloop()

A huge part of this code comes from this topic : How do I enable multiple selection of values from a combobox?

For now it works for the second combobox but there is an error on the first:

Traceback (most recent call last):
  File "C:\", line 1892, in __call__
    return self.func(*args)
  File "c:dbcreation.py", line 285, in show
    value.append(self.choices[choice].get())
KeyError: 'Manual'
7
  • When you change k, content of data[k][i] changes as well. Therefore show of the first combobox iterates over other data than the constructor which built the self.choices dict. Commented Jun 20, 2024 at 14:08
  • What are nom[k][i] and data[k][i] ? Looks like you haven't included in the code Commented Jun 20, 2024 at 14:16
  • True, updated thanks :) Commented Jun 20, 2024 at 14:33
  • Maybe first use print() (and print(type(...)), print(len(...)), etc.) to see which part of code is executed and what you really have in variables. It is called "print debugging" and it helps to see what code is really doing. Commented Jun 20, 2024 at 22:53
  • you created class but you keep all information outside this class and you don't use self. to keep it inside class - so why do you need class? Why do you set i and k outside class? It should be hidden inside class. And if you need different values then send it as parameters in Combo(root, i=0, k=1) Commented Jun 20, 2024 at 22:57

1 Answer 1

0

Frankly I don't know what is the problem because first I change how it works - to make it more readable.

But later I released that problem can be because you use external variable k in both Combo. When you set k = 1 to create second Combo then this value 1 will be used in first Combo too. You have to assign value to self.k inside class and use only this self.k inside class. You should send all values explicitly as parameters and you should keep them in class variables.


First I put all data directly in dictionary without using some data[0]or other variable nom

data = {
    'Part': ['01_Flat', '02_Curv', '03_RX', '04_RY', '05_RZ', '06_Fsyr', '07_AI'],
    'Cutting': ['Manual', 'Laser', 'Gamma', 'Proto']
}

Next I send explicitly key and data to Combo

Combo(root, text='Part', options=data['Part'])

And later I keep all elements inside class using self. - I don't access external data. And when I have Combo assigned to variable then I can get all information directly from Combo - combo_a.key, combo_a.data and I don't have to search it in other objects.

And I use readable variable text instead of k (and I don't need variable i)

class Combo(tk.Frame):

    def __init__(self, parent, text, options):
        tk.Frame.__init__(self, parent)
        
        self.text = text
        self.options = options

        self.menubutton = tk.Menubutton(self, text=self.text, 
                                        indicatoron=True, borderwidth=1, relief="raised")
                                    
        self.menu = tk.Menu(self.menubutton, tearoff=False)
        self.menubutton.configure(menu=self.menu)
        self.menubutton.pack(padx=10, pady=10)

        self.choices = {}
        for item in self.options:
            self.choices[item] = tk.BooleanVar(value=False)
            self.menu.add_checkbutton(label=item, variable=self.choices[item], 
                                  onvalue=True, offvalue=False, command=self.show)

and I also changed function show() to use self.options and self.choices

def show(self):
    values = [self.choices[item].get() for item in self.options]
    print(values)
    return values

Because this functions gives list of 0,1 (in my version True, False`) which is unreadable so I created function which create list only with selected elements

def get_selected(self):
    values = [item for item in self.options if self.choices[item].get() is True ]
    return values

And all works without problems.


Full working code:

import tkinter as tk
from tkinter import ttk

# --- classes ---

class Combo(tk.Frame):

    def __init__(self, parent, text, options):
        tk.Frame.__init__(self, parent)
        
        self.text = text
        self.options = options

        self.menubutton = tk.Menubutton(self, text=self.text, 
                                        indicatoron=True, borderwidth=1, relief="raised")
                                    
        self.menu = tk.Menu(self.menubutton, tearoff=False)
        self.menubutton.configure(menu=self.menu)
        self.menubutton.pack(padx=10, pady=10)

        self.choices = {}
        
        for item in self.options:
            self.choices[item] = tk.BooleanVar(value=False)
            self.menu.add_checkbutton(label=item, variable=self.choices[item], 
                                  onvalue=True, offvalue=False, command=self.show)

    def show(self):
        value = [self.choices[item].get() for item in self.options]
        print(value, self.get_selected())
        return value

    def get_selected(self):
        value = [item for item in self.options if self.choices[item].get() is True ]
        return value

# --- functions ---

def show_all_selections():
    results.delete('0.0', 'end')
    results.insert('end', f'{combo_a.text}: {combo_a.get_selected()}\n')
    results.insert('end', f'{combo_pos.text}: {combo_pos.get_selected()}\n')

# --- main ---    

data = {
    'Part': ['01_Flat', '02_Curv', '03_RX', '04_RY', '05_RZ', '06_Fsyr', '07_AI'],
    'Cutting': ['Manual', 'Laser', 'Gamma', 'Proto']
}

root = tk.Tk()

canva = tk.Canvas(root, width=530, height=200)
canva.pack(fill="both", expand=True)

combo_a = Combo(root, text='Part', options=data['Part'])
a = canva.create_window(125, 50, anchor="nw", window=combo_a)

combo_pos = Combo(root, text='Cutting', options=data['Cutting'])
pos = canva.create_window(225, 50, anchor="nw", window=combo_pos)

results = tk.Text(root, height=4)
results.pack()

button = tk.Button(root, text="Show all selected", command=show_all_selections)
button.pack()

root.mainloop()

enter image description here

(it seems Stackoverflow has problem to display images)


PEP 8 -- Style Guide for Python Code

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

Comments

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.