Python Tkinter OptionMenu: Changing, deleting, adding more choice options

Friday, June 19, 2009

In my last blog related to Python Tkinter OptionMenu, we have seen the way to add options using the OptionMenu object and display them, in this listing, we will see how to add/change/delete options from OptionMenu on the fly. The python tkinter OptionMenu is a convenient object for holding multiple choice values, typically this is used in GUI programming to enable an user to select a value among multiple choices.

However, as I thought initially, its not a trivial task to edit/delete/add new options to OptionMenu since there isn't a convenient method to do so, initially when you create an OptionMenu, you need to create that object with all possible choices and then to change/delete/add more choices, one should use the add_command method of OptionMenu's menu object (which is a tkinter Menu), the below code does the same.

1.  # File name: tkinterOptionMenuDemo.py
2. # Changing/adding/deleting options to OptionMenu on the fly
3. # Author: S.Prasanna
4.
5. from Tkinter import *
6. import tkMessageBox
7.
8. def displayOption():
9. """ Display the OptionMenu selection. """
10.
11. global optionMenuWidget, DEFAULTVALUE_OPTION
12.
13. if (optionMenuWidget.cget("text") == DEFAULTVALUE_OPTION):
14. tkMessageBox.showerror("Tkinter OptionMenu Widget", "Select a valid option.")
15. else:
16. tkMessageBox.showinfo("Tkinter OptionMenu Widget", "OptionMenu value = " + optionMenuWidget.cget("text"))
17.
18. def addMenuOptions():
19. """ Add Menu options dynamically """
20.
21. global optionMenuWidget
22.
23. optionMenuWidget["menu"].delete(0, END)
24. # Add options from 1 to 5
25. for i in range(1, 6):
26. optionMenuWidget["menu"].add_command(label=i, command=lambda temp = i: optionMenuWidget.setvar(optionMenuWidget.cget("textvariable"), value = temp))
27.
28. if __name__ == "__main__":
29.
30. root = Tk()
31. DEFAULTVALUE_OPTION = "Select an option."
32.
33. root.title("Tkinter OptionMenu Widget")
34. root["padx"] = 40
35. root["pady"] = 20
36.
37. # Create an Option frame to hold the option Label and the optionMenu widget
38. optionFrame = Frame(root)
39.
40. #Create a Label in textFrame
41. optionLabel = Label(optionFrame)
42. optionLabel["text"] = "OptionsMenu demo"
43. optionLabel.pack(side=LEFT)
44.
45. # Create an optionMenu Widget in the optionFrame
46. optionTuple = ("",)
47.
48. defaultOption = StringVar()
49. optionMenuWidget = apply(OptionMenu, (optionFrame, defaultOption) + optionTuple)
50. addMenuOptions()
51. defaultOption.set(DEFAULTVALUE_OPTION)
52. optionMenuWidget["width"] = 15
53. optionMenuWidget.pack(side=LEFT)
54.
55. optionFrame.pack()
56.
57. button = Button(root, text="Submit", command=displayOption)
58. button.pack()
59.
60. root.mainloop()
Sample Output:


Explanation:

The code here is similar to the one discussed in the tkinter OptionMenu and its usage blog where we create an OptionMenu and initialize it with a list of choice options, here we do the same where we initialize the OptionMenu with an empty value "" (line 46), then remove that value (line 23) and add more options (line 24 - 26).

The code segment which is of interest here is
23.     optionMenuWidget["menu"].delete(0, END)
24. # Add options from 1 to 5
25. for i in range(1, 6):
26. optionMenuWidget["menu"].add_command(label=i, command=lambda temp = i: optionMenuWidget.setvar(optionMenuWidget.cget("textvariable"), value = temp))
Line 23 removes all option choices from the OptionsMenu's menu property, line 25 - 26 adds five option choices using the add_command method of OptionMenu's menu property, the code
command=lambda temp = i: optionMenuWidget.setvar(optionMenuWidget.cget("textvariable"), value = temp)
initializes a command which executes an inline lambda function which sets the OptionMenu's control variable (got using optionMenuWidget.cget("textvariable")) to the option label or choice value (using the setvar method).

5 comments:

Michael said...

Great post. This is exactly what I'm looking for, except for one thing -- as far as I can tell, when you make the OptionMenu choices 'on the fly' the way you did, you lose the ability to set the OptionMenu's command. It is used up by the lambda function that changes the text of the OptionMenu. I wanted to also have a different function called whenever the user selected something with the OptionMenu, but I can't figure out how to do so. Any ideas?

Prasanna Seshadri said...

Thanks Michael for the comments, thats a good question you asked, I will respond once I find a solution.

Michael said...
This comment has been removed by the author.
Michael said...

Prasanna, as a quick fix, I decided to set the menu item's command to the function that I wanted to be called when the user changes selections with the OptionMenu, and then put the line to set the dropdown's text in that function that is called. E.g.

def optionMenuChanged(event):
optionMenuWidget.setvar(unitNo_dropdown.cget("textvariable"), value = event)
#code to do what I originally wanted to do when the OptionMenu was changed
.
.
.
optionMenuWidget['menu'].add_command(label=myLabel, command=lambda temp=myLabel: unitNameChange(temp))

(I hope that code shows up legibly in the comments section!) Anyway, not the most elegant solution in the world, but it does what it needs to. Still, perhaps you can think of a better way. I also found Python MegaWidgets in my search for a solution, and though I haven't tried them out yet, it looks like the Pmw.ComboBox() might be a nice way to do it.

Raquel Peres da Silva said...

Thank you so much! Line 26 is exactly what I've been looking for.


Copyright © 2016 Prasanna Seshadri, www.prasannatech.net, All Rights Reserved.
No part of the content or this site may be reproduced without prior written permission of the author.