如何动态替换wxpython中的菜单栏?

How to dynamically replace the menubar in wxpython?

我正在用 wxpython 制作像 AmCap 这样的相机查看器。现在我正在制作一个菜单栏,显示已连接的摄像机列表。(如 AMCAP 设备菜单,见图 1)

这是我的代码:(get_all_devices returns 已连接设备列表,它工作正常)

class MainFrame(wx.Frame):
    def __init__(self, parent, fid, title, size):
        wx.Frame.__init__(self, parent, fid, title, wx.DefaultPosition, size)

        self.devices = get_all_devices()
        # init menubar
        self.make_menubar()

        # set timer to check usb connectivity
        self.timer = wx.Timer(self)
        self.timer.Start(100) 
        self.Bind(wx.EVT_TIMER, self.check_device)

    def make_menubar(self):
        self.menubar = wx.MenuBar()
        self.devices_menu = wx.Menu()
        self.options_menu = wx.Menu()
        help_menu = wx.Menu()
        self.make_devices_menu()

        self.options_menu.Append(101, 'resolutions')
        self.menubar.Append(self.devices_menu, 'devices')
        self.menubar.Append(self.options_menu, 'options')
        self.menubar.Append(help_menu, 'help')

        self.SetMenuBar(self.menubar)

    def recreate_menubar(self):
        self.menubar.Destroy()
        self.make_menubar()
        self.Layout()
        self.Refresh()

    def make_devices_menu(self):
        for i in range(len(self.devices)):
            self.devices_menu.Append(CI.MENU_DEVICES + 1 + i, self.devices[i], kind=wx.ITEM_CHECK)
            self.Bind(wx.EVT_MENU, self.click_device_menu, id=CI.MENU_DEVICES + 1 +  i)

    def check_device(self, evt):
        cur_devices = get_all_devices()
        if set(self.devices) != set(cur_devices):
            self.devices = cur_devices
            self.recreate_menubar()

它一开始确实有效,但如果我尝试断开和连接相机 4~5 次,它不会重新创建菜单栏。例如,假设有两个连接的摄像头,如图 1 所示。如果我断开第一个摄像头,程序将如图 2 所示。(只剩下一个摄像头)。然后,如果我再次连接相机,它将再次显示两个相机,如图 1 所示。这是我所期望的。(图 1 - 断开连接 -> 图 2 - 连接 -> 图 1)

但实际上,4~5次后,就不能正常使用了。它不会更新菜单栏。(图 1 - 断开连接 -> 图 2 - 再次连接 -> 图 2!)

我做错了什么? wxpython中不允许吗?

如果您需要我的代码的更多信息,请告诉我。

欢迎任何提示! 提前致谢。

图 1

图 2

编辑:

我发现如果我在init的末尾添加这样的代码:

self.menubar.SetName(str(self.devices))
self.SetMenuBar(self.menubar)
print(self.menubar.GetName())
print(self.GetMenuBar().GetName())

它 returns 相同的已连接摄像机列表。所以我认为 wxpython 可以正确地制作和设置菜单栏。

虽然重新创建整个菜单栏看起来有点过分(您可以只重新创建设备菜单,或者您甚至可以删除旧的相机项目并添加新的项目,甚至不这样做),它应该仍然有效。

您是否检查过您的 recreate_menubar() 是否按预期被调用?您可以从中显示一个消息框以确保。如果它被调用但不知何故不更新菜单栏,最好的办法是尝试在 SSCCE and open a ticket on wxTrac 中重现该问题,以便可以对其进行调试并有望修复(如果您需要,请提及您的平台这样做)。