我正在wxPython中为I2C设备编写一个更大的GUI应用程序。当程序启动时,它会从XML文件动态生成一个设备菜单。它首先为每个"类型"的设备(EEPROM、多路复用器、IOExpander等)添加一个子菜单,然后在每个子菜单中添加实际设备的名称。因为菜单直到运行时才创建,所以我必须动态分配ID。此外,由于XML文件将不时使用新的"类型"设备进行更新,我不仅需要知道选择了哪个项目,还需要知道该项目来自哪个子菜单。我目前实现这一点的方式是在我分配项目的ID中建立"父子"关系。目前,其中一个菜单项的ID是一个3位数:第一个数字总是2,所以我知道它来自设备菜单。第二个数字是选择的子菜单,最后一个数字是所选的特定设备。为了存储这些ID,我将它们添加到字典中,其中ID是密钥,设备名称是值。
submenu_id = -1
for device_type in self.device_list:
submenu = wx.Menu()
submenu_id += 1
device_menu_id = -1
for device in device_type.m_device_list:
device_menu_id += 1
device_id = 200 + (submenu_id * 10) + device_menu_id
id_list[device_id] = device.m_name
item = wx.MenuItem(submenu, device_id, device.m_name, wx.EmptyString, wx.ITEM_NORMAL)
submenu.AppendItem(item)
menu.AppendSubMenu(submenu, device_type.m_name)
现在,我有两个问题。最直接的问题是,我需要保留从200到299的ID范围,其中包括可以分配给设备项目的所有可能的ID。如果我叫wx。ID_ANY,它有时会为其他菜单分配该范围内的ID,这意味着我的绑定都搞砸了。另一个问题是,我觉得这样做有点做作。目前,我只能有10个不同类型的设备子菜单,每个子菜单中只有10个设备。在可预见的未来,这应该足够了,但我希望能够在尽可能多的不同类别中添加尽可能多地设备。此外,这样做的代码非常丑陋和模糊,我真的希望有人阅读我的代码,知道我到底在做什么。
所以,我的第一个问题是:有没有办法保留我需要的ID范围,这样我就不会与wx发生任何冲突?
我的第二个问题是,有更好的方法吗?
参见wx.RegisterId(id)
。简而言之,wx.NewId
的头脑相当简单。它只是增加一个内部计数器并返回值,而不需要额外的智能。如果您使用wx.RegisterId(id)
,那么该计数器将被设置为给定的值,因此wx.NewId
返回的下一个值将是>id。因此,您可以将其设置为某个值,然后低于该值的所有内容(尚未保留给系统id,如wx.id_OK)都可以被代码用作显式id。但是,请注意,如果您在应用程序运行的整个生命周期中使用数千个wx.ID_ANY
或wx.NewID()
ID,则自动ID可能会循环使用。
至于更好的方法,我想我只需要使用wx.ID_ANY
,然后使用字典将分配给该项目的菜单id映射到实际数据obect。这样,ID(实际上只是与UI相关的实现细节,而不是数据模型)本身就没有真正的意义,但它们可以在菜单事件处理程序中使用,以轻松获取与应用程序相关的真实数据。例如:
item = menu.Append(wx.ID_ANY, "Foo")
self.menuIdMap[item.GetId()] = someDataObjectForFoo
self.Bind(wx.EVT_MENU, self.OnMenuItemSelected, item)
然后:
def OnMenuItemSelected(self, evt):
dataObj = self.menuIdMap[evt.GetId()]
dataObj.doSomething()