Tkinter optionmenu add_command 字符串在选择时不显示在小部件上

Tkinter optionmenu add_command strings do not show on widget when selected

from tkinter import *


main = Tk()

var = StringVar()
options = OptionMenu(main, var, 'option1')
options.grid()
options['menu'].add_command(label='option2')


main.mainloop()

当您在菜单中 select 'option1' 时,它会在小部件上显示该字符串。如果您 select 'option2' 它不会在小部件上显示该字符串。如果您为选项 2 设置命令,它将 运行。为什么 'option2' 在 selected 时没有显示在小部件中?

python 3.5

更新:

通过 for 循环添加字符串,我 运行 解决了每个字符串的命令使用相同变量的问题。

from tkinter import *

def _print(var, string):
    print(string)
    var.set(string)

lst = ['hello', 'bob', 'testing']

main = Tk()
var = StringVar()
options = OptionMenu(main, var, 'option1')
options.grid()

for string in lst:
    options['menu'].add_command(label=string, command=lambda: _print(var, string))

main.mainloop()

我尝试在循环中使用 lambda event, i=string: _print(var, i)),但 lamdba 不喜欢它。说它丢失了 'event'。我已经将事件放在 _print 函数中并调用了 _print 但我得到了 lamdba 缺少事件的相同错误。知道如何为循环中的每个命令传递正确的变量吗?

当您在 Optionmenu() 小部件中声明 'option2' 时它会起作用。更多示例可以从 here and here.

中阅读
from tkinter import *

main = Tk()

var = StringVar()
options = OptionMenu(main, var, 'option1', 'option2')
options.grid()
#options['menu'].add_command(label='option2')


main.mainloop()

我发现 menu 选项用于在 Menu() 小部件中创建项目,但不适用于 Optionmenu() 小部件。这表示 here. You can read more about how to declare a .Menu() widget here。祝你的 tkinter 发展一切顺利。

编辑1:

失败的原因是您没有声明与 .add_command 方法关联的 command 选项。单独完成此操作后,您会注意到 Optionmenu 仍未使用添加的菜单项的新标签进行更新。要解决此问题,您必须使用控制变量 StringVar.set() 方法来进行更新。请参阅下面修改后的脚本。

from tkinter import *

def _print1(value):
    # By default, callback to OptionMenu has a positional argument for the 
    #  menu item's label. 
    print(value)
    print(var.get())
    
def _print2():
    var.set('option2')
    print(var.get())

main = Tk()

var = StringVar()
options = OptionMenu(main, var, 'option1',command=_print1)
options.grid()
options['menu'].add_command(label='option2', command=_print2)
# To add more clickable menu items, the 'add_command' method requires you to
# to declare it's options 'label' and 'command'.

main.mainloop()

编辑2:

  1. 注意,我在 Edit1 中将 command 方面添加到 options。我 没有更早解决,但认为需要展示 完整性。
  2. 在你的更新中回答你的问题,做你想做的,我 将脚本重写为 class 对象。我还使用了内部 class _setit 在 tkinter 中找到,OptionMenu 小部件曾经用于 请配置 command 使用的回调。这种方法克服了你遇到的问题。

修改后的代码:

from tkinter import *

class App(Tk):

    def __init__(self, parent=None):
        Tk.__init__(self, parent)
        self.parent=parent
        self.createOM()
        self.grid()

    def createOM(self):
        # Create OptionMenu
        omlist=['option1']
        self.var = StringVar()
        self.options = OptionMenu(self, self.var, *omlist,
                                  command=self._print1)
        self.options.grid()
        
        values = ['hello', 'bob', 'testing']
        for v in values:
            self.options['menu'].add_command(
                label=v, command=_setit(self.var, v, self._print2))
        # To add more clickable menu items, the 'add_command' method requires you to
        # to declare it's options 'label' and 'command'.
       
    def _print1(self, value, *args):
        #callback for OptionMenu has these arguments because inherently it
        #uses the _setit class to configure the callback with these arguments. 
        print()        
        print(value)        
        #self.var.set('option10') #Uncomment to change OptionMenu display
        print(self.var.get())

    def _print2(self, value, *args):
        print()        
        print(value)        
        #self.var.set('option20') #Uncomment to change OptionMenu display
        print(self.var.get())
   
#The following class is extracted from tkinter.
class _setit:
    """Internal class. It wraps the command in the widget OptionMenu."""
    def __init__(self, var, value, callback=None):
        self.__value = value
        self.__var = var
        self.__callback = callback
    def __call__(self, *args):
        self.__var.set(self.__value)
        if self.__callback:
            self.__callback(self.__value, *args)


if __name__ == "__main__":
    app = App()
    app.mainloop()

它没有 select 任何东西,因为 它不应该 。你基本上是在破解 OptionMenu 的视觉部分。您作为 values 传递的项目首先添加到菜单,然后提供修改 selection 的命令选项。当您调用 options['menu'].add_command(label='option2') 时,您基本上只是在修改小部件的可视部分,'option2' 而不是 添加到值中,因此命令选项 没有设置。自己看源码here.