14

I have an OptionMenu in my GUI that is being populated by a list. Every time the user runs a certain process the list updates to reflect this. Is there a way to update the OptionMenu based on the list? I've tried self.plotWindow.update() as per this question but to no avail. However, closing and reopening the window does refresh the OptionMenu as you would expect. Relevant code:

if self.figNum.get() == 'New Figure...':
    if self.figList[-1] == 'New Figure...':
        self.figList.append(1)
    else:
        self.figList.append(self.figList[-1]+1)
    self.plotWindow.update() #tk.Tk() window
    self.i = self.figList[-1]
else:
    self.i = self.figNum.get()
stovfl
  • 14,998
  • 7
  • 24
  • 51
wes3449
  • 305
  • 1
  • 2
  • 10
  • I know it's not what you were looking for, but after a lot of searching I settled for the tkinter.Combobox which does the same job and is more accessible. https://stackoverflow.com/questions/18906047/how-to-update-values-to-the-listbox-under-combobox-in-ttk-python33 – BSD Nov 15 '22 at 20:48

2 Answers2

21

The options in an OptionMenu are not bound to the list from which they are created. Therefore, changing the list does not change the OptionMenu, you'll have to update it yourself.

You can do that by getting the OptionMenu's menu, and add commands to that. The following example shows how to do this (based on this answer).

It shows that, even though the self.options list is appended with an option using the 'Add option to list' button, the OptionMenu does not change automatically. To update the OptionMenu, you can use the 'Update option menu' button for this, which calls self.update_option_menu. This function deletes all options from the OptionMenu, and inserts a new one for each item in self.options.

import Tkinter as tk

class App():
    def __init__(self, parent):
        self.parent = parent
        self.options = ['one', 'two', 'three']

        self.om_variable = tk.StringVar(self.parent)
        self.om_variable.set(self.options[0])
        self.om_variable.trace('w', self.option_select)

        self.om = tk.OptionMenu(self.parent, self.om_variable, *self.options)
        self.om.grid(column=0, row=0)

        self.label = tk.Label(self.parent, text='Enter new option')
        self.entry = tk.Entry(self.parent)
        self.button = tk.Button(self.parent, text='Add option to list', command=self.add_option)

        self.label.grid(column=1, row=0)
        self.entry.grid(column=1, row=1)
        self.button.grid(column=1, row=2)

        self.update_button = tk.Button(self.parent, text='Update option menu', command=self.update_option_menu)
        self.update_button.grid(column=0, row=2)

    def update_option_menu(self):
        menu = self.om["menu"]
        menu.delete(0, "end")
        for string in self.options:
            menu.add_command(label=string, 
                             command=lambda value=string: self.om_variable.set(value))

    def add_option(self):
         self.options.append(self.entry.get())
         self.entry.delete(0, 'end')
         print self.options

    def option_select(self, *args):
        print self.om_variable.get()


root = tk.Tk()
App(root)
root.mainloop()
Community
  • 1
  • 1
fhdrsdg
  • 10,297
  • 2
  • 41
  • 62
  • This is perfect, thank you! I don't really understand *why* it works (I tried implementing it differently and it failed) but it works nonetheless and that's good enough for me. – wes3449 Feb 09 '15 at 15:50
  • What part *exactly* don't you understand? I could try to explain that some more. – fhdrsdg Feb 09 '15 at 15:55
  • Mostly just the fact that we're adding a command instead of a string. (Though I guess since we do `command = lambda` it becomes a command that doesn't do anything). I'm referring to the `update_option_menu` function, everything else makes sense. – wes3449 Feb 09 '15 at 16:04
  • The OptionMenu is basically a [Menu](http://effbot.org/tkinterbook/menu.htm) widget. To access the Menu of an OptionMenu, you use `self.om['menu']`. The `add_command` method is the same as from a normal Menu. What the Menu entries do is changing the variable associated with the OptionMenu to the value they represent. – fhdrsdg Feb 09 '15 at 19:44
0

I believe a simple solution to update the OptionMenu would be to use the configure function built into the class like so:

my_option_menu.configure(window, user_choice, *updated_list)
  • Sorry, what is window and user_choice i your example? – mm_ Dec 23 '21 at 18:04
  • 1
    Did not work as shown. OptionMenu has a configure that takes two arguments and is NOT meant to be updated in this fashion. – BSD Nov 15 '22 at 20:47