How do I enable multiple selection of values from a combobox?
13,218
Solution 1
By design the ttk combobox doesn't support multiple selections. It is designed to allow you to pick one item from a list of choices.
If you need to be able to make multiple choices you can use a menubutton with an associated menu, and add checkbuttons or radiobuttons to the menu.
Here's an example:
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
menubutton = tk.Menubutton(self, text="Choose wisely",
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 ("Iron Man", "Superman", "Batman"):
self.choices[choice] = tk.IntVar(value=0)
menu.add_checkbutton(label=choice, variable=self.choices[choice],
onvalue=1, offvalue=0,
command=self.printValues)
def printValues(self):
for name, var in self.choices.items():
print "%s: %s" % (name, var.get())
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
Solution 2
Try this maybe...
import tkinter as Tkinter
import tkinter.font as tkFont
import tkinter.ttk as ttk
class Picker(ttk.Frame):
def __init__(self, master=None,activebackground='#b1dcfb',values=[],entry_wid=None,activeforeground='black', selectbackground='#003eff', selectforeground='white', command=None, borderwidth=1, relief="solid"):
self._selected_item = None
self._values = values
self._entry_wid = entry_wid
self._sel_bg = selectbackground
self._sel_fg = selectforeground
self._act_bg = activebackground
self._act_fg = activeforeground
self._command = command
ttk.Frame.__init__(self, master, borderwidth=borderwidth, relief=relief)
self.bind("<FocusIn>", lambda event:self.event_generate('<<PickerFocusIn>>'))
self.bind("<FocusOut>", lambda event:self.event_generate('<<PickerFocusOut>>'))
self._font = tkFont.Font()
self.dict_checkbutton = {}
self.dict_checkbutton_var = {}
self.dict_intvar_item = {}
for index,item in enumerate(self._values):
self.dict_intvar_item[item] = Tkinter.IntVar()
self.dict_checkbutton[item] = ttk.Checkbutton(self, text = item, variable=self.dict_intvar_item[item],command=lambda ITEM = item:self._command(ITEM))
self.dict_checkbutton[item].grid(row=index, column=0, sticky=Tkinter.NSEW)
self.dict_intvar_item[item].set(0)
class Combopicker(ttk.Entry, Picker):
def __init__(self, master, values= [] ,entryvar=None, entrywidth=None, entrystyle=None, onselect=None,activebackground='#b1dcfb', activeforeground='black', selectbackground='#003eff', selectforeground='white', borderwidth=1, relief="solid"):
if entryvar is not None:
self.entry_var = entryvar
else:
self.entry_var = Tkinter.StringVar()
entry_config = {}
if entrywidth is not None:
entry_config["width"] = entrywidth
if entrystyle is not None:
entry_config["style"] = entrystyle
ttk.Entry.__init__(self, master, textvariable=self.entry_var, **entry_config, state = "readonly")
self._is_menuoptions_visible = False
self.picker_frame = Picker(self.winfo_toplevel(), values=values,entry_wid = self.entry_var,activebackground=activebackground, activeforeground=activeforeground, selectbackground=selectbackground, selectforeground=selectforeground, command=self._on_selected_check)
self.bind_all("<1>", self._on_click, "+")
self.bind("<Escape>", lambda event: self.hide_picker())
@property
def current_value(self):
try:
value = self.entry_var.get()
return value
except ValueError:
return None
@current_value.setter
def current_value(self, INDEX):
self.entry_var.set(values.index(INDEX))
def _on_selected_check(self, SELECTED):
value = []
if self.entry_var.get() != "" and self.entry_var.get() != None:
temp_value = self.entry_var.get()
value = temp_value.split(",")
if str(SELECTED) in value:
value.remove(str(SELECTED))
else:
value.append(str(SELECTED))
value.sort()
temp_value = ""
for index,item in enumerate(value):
if item!= "":
if index != 0:
temp_value += ","
temp_value += str(item)
self.entry_var.set(temp_value)
def _on_click(self, event):
str_widget = str(event.widget)
if str_widget == str(self):
if not self._is_menuoptions_visible:
self.show_picker()
else:
if not str_widget.startswith(str(self.picker_frame)) and self._is_menuoptions_visible:
self.hide_picker()
def show_picker(self):
if not self._is_menuoptions_visible:
self.picker_frame.place(in_=self, relx=0, rely=1, relwidth=1 )
self.picker_frame.lift()
self._is_menuoptions_visible = True
def hide_picker(self):
if self._is_menuoptions_visible:
self.picker_frame.place_forget()
self._is_menuoptions_visible = False
if __name__ == "__main__":
import sys
try:
from Tkinter import Tk, Frame, Label
except ImportError:
from tkinter import Tk, Frame, Label
root = Tk()
root.geometry("500x600")
main =Frame(root, pady =15, padx=15)
main.pack(expand=True, fill="both")
Label(main, justify="left", text=__doc__).pack(anchor="w", pady=(0,15))
COMBOPICKER1 = Combopicker(main, values = [1, 2, 3, 4])
COMBOPICKER1.pack(anchor="w")
if 'win' not in sys.platform:
style = ttk.Style()
style.theme_use('clam')
root.mainloop()
Author by
jknicely
Updated on June 04, 2022Comments
-
jknicely almost 2 years
Python 3.4.3, Windows 10, Tkinter
I am attempting to create a combobox that allows for multiple selections from the dropdown. I have found similar work for listbox (Python Tkinter multiple selection Listbox), but cannot get it work with the combobox.
Is there a simple way to enable multiple selection from the dropdown of the combobox?
-
kakyo over 5 yearsTrying this example... However, on macOS 10.13.6 and Python 3.7.1 Homebrew, clicking on the menu items gives me messy result, the checkmarks appear and disappear not according to the assumed logic as you click on each item.