[Tkinter-discuss] optionmenu insert

Michael Lange klappnase at web.de
Wed May 3 11:29:12 CEST 2006


On Tue, 02 May 2006 14:32:17 +0200
Pavel Kosina <geon at post.cz> wrote:


> Just found there is another trouble with this. Maybe I could help 
> myself, but dont know how to get from tk documentation what you have 
> written - how to know why "command" should be there, why ["menu"], etc.
> 

Hi Pavel,

the  "menu" key is created in Tkinter's OptionMenu class to give us access
to the Menu subwidget; optionmenu["menu"] is equivalent with optionmenu.__menu .
"command" is there to tell tk what to insert into the menu; try:

    optionmenu["menu"].insert('end', 'blah')

and you get a TclError:

    _tkinter.TclError: bad menu entry type "blah": must be cascade, checkbutton, command, radiobutton, or separator


> Anyway, I have:
> 
> w = OptionMenu(root, var,u"one", u"two", u"...",command=ok)
> w.pack()
> w["menu"].insert(2, "command", label=u"three")
> 
> When I choose "three" then, the function 'ok' is not called. It must be 
> another argument in last line, I think.
> 

Oops, you are right. A look at Tkinter.OptionMenu shows that it is not that trivial.
Tkinter wraps the command in its internal _setit class, so it should actually be:

    from Tkinter import _setit
    w['menu'].insert('end', 'command', label='blah', command=_setit(var, 'blah', ok))

The arguments for the _setit constructor are: _setit(variable, value, callback) .

Not very nice, indeed. Maybe it would be a nice improvement to Tkinter to add at least
an insert() and a delete() method to Tkinter.OptionMenu .

If you do not want to use the "hidden" _setit() you might define another callback for the inserted items:

    def ok_new(value):
        var.set(value)
        ok(value)

    w['menu'].insert('end', 'command', label='blah', command=lambda : ok_new('blah'))

Maybe it is even nicer not to use an OptionMenu command at all and use a trace callback for the variable instead:

>>> v = StringVar()
>>> v.set('a')
>>> def ok(*args):
...     print v.get()
... 
>>> v.trace('w', ok)
'-1216076380ok'
>>> om = OptionMenu(r, v, 'a', 'b', 'c')
>>> om.pack()
>>> om['menu'].insert('end', 'command', label='foo', command=lambda : v.set('foo'))

At least you do not need a second callback this way.

I hope this helps

Michael




More information about the Tkinter-discuss mailing list