wxPython:带有动态数据的 PopupMenu

问题描述

我有下面的代码。 最终目标是,PopupMenu 的内容可以在您单击时延迟。 内容将从文件中加载并放入选项中。 这样可行。 我将问题限制在下面的代码中。 所期望的是,当您在框架中单击鼠标右键时,您会得到一个带有 2 个选项“menu1”和“menu2”的 PopupMenu。这样可行。 如果您选择“菜单 1”,则应打印“命令 1”,而对于“菜单 2”,则应打印“命令 2” 但两个选项都会打印“命令 2”。

有什么帮助吗?

import wx


def on_right_click(event):
    menu = wx.Menu()
    options = [{'msg': 'menu1','cmd': 'command 1'},{'msg': 'menu2','cmd': 'command 2'}]
    for option in options:
        menu_item = menu.Append(wx.ID_ANY,option['msg'])
        menu.Bind(
            event=wx.EVT_MENU,handler=lambda x: print(option['cmd']),source=menu_item
        )
    frame.PopupMenu(menu,event.GetPosition())
    menu.Destroy()


app = wx.App()
frame = wx.Frame(parent=None,title='Hello World')
frame.Bind(wx.EVT_RIGHT_DOWN,on_right_click)

frame.Show()
app.MainLoop()

解决方法

lambda 中的变量值是在执行时计算的,因此返回值总是最后一个值的结果。
您可以通过使用索引并将其增加到无效的索引值来测试这一点,所有 lambda 都将因索引错误而失败。
答案是扩展您的 lambda 参数以修复该值。
例如

import wx

def on_right_click(event):
    menu = wx.Menu()
    options = [{'msg': 'menu1','cmd': 'command 1'},{'msg': 'menu2','cmd': 'command 2'},{'msg': 'menu3','cmd': "I can't believe"},{'msg': 'menu4','cmd': "it's not butter"}]
    for option in options:
        menu_item = menu.Append(wx.ID_ANY,option['msg'])
        menu.Bind(
            event=wx.EVT_MENU,handler=lambda x,current_cmd = option['cmd']: print(current_cmd),source=menu_item
        )
    frame.PopupMenu(menu,event.GetPosition())
    menu.Destroy()


app = wx.App()
frame = wx.Frame(parent=None,title='Right Click to Test')
frame.Bind(wx.EVT_RIGHT_DOWN,on_right_click)

frame.Show()
app.MainLoop()

请参阅此相关帖子:position in a list with bind and wxpython