Ответьте на ListCTRL изменить ровно один раз
Вопрос
Я работаю над формой, используя WxPython, где я хочу, чтобы список значений ListCtrl изменить на основе выбора другого listctrl. Для этого я использую методы, связанные с контрольным объектом EVT_LIST_ITEM_SELECTED
а также EVT_LIST_ITEM_DESELECTED
События для вызова Publisher.sendMessage
. Отказ Контроль, который должен быть изменен, имеет метод, который является подписчиком для этого издателя. Это работает: когда нажал первый listctrl, второй обновляется.
Проблема в том, что данные должны быть обновлены из базы данных, и сообщение отправляется на каждый выбор и отмените. Это означает, что даже если я просто нажимаю на один элемент, база данных запрашивается дважды (один раз для отмените, затем снова для выбора). Если я Shift-Щелкните к Multi-Select 5 элементов, то 5 вызовов. Есть ли способ иметь ответ «listCtrl» на множество, а не на отдельные выборы?
Решение
Лучшее решение, кажется, нужно использовать wx.CallAfter
С флагом для выполнения процедуры последующей деятельности ровно один раз:
import wx
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.list_ctrl_1 = wx.ListCtrl(self, -1, style=wx.LC_REPORT|wx.SUNKEN_BORDER)
sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
sizer_1.Add(self.list_ctrl_1, 1, wx.EXPAND, 0)
self.list_ctrl_1.InsertColumn(0,"1")
self.list_ctrl_1.InsertStringItem(0,"HELLO1")
self.list_ctrl_1.InsertStringItem(0,"HELLO2")
self.list_ctrl_1.InsertStringItem(0,"HELLO3")
self.list_ctrl_1.InsertStringItem(0,"HELLO4")
self.list_ctrl_1.InsertStringItem(0,"HELLO5")
self.list_ctrl_1.InsertStringItem(0,"HELLO6")
self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list_ctrl_1)
self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self.list_ctrl_1)
self.dirty = False
def Cleanup(self, StringToPrint):
print 'No Longer Dirty!'
self.dirty = False
def OnItemSelected(self,event):
print str(self.__class__) + " - OnItemSelected"
if not self.dirty:
self.dirty = True
wx.CallAfter(self.Cleanup)
event.Skip()
def OnItemDeselected(self,event):
print str(self.__class__) + " - OnItemDeselected"
if not self.dirty:
self.dirty = True
wx.CallAfter(self.Cleanup)
event.Skip()
if __name__ == "__main__":
app = wx.PySimpleApp(0)
wx.InitAllImageHandlers()
frame_1 = MyFrame(None, -1, "")
app.SetTopWindow(frame_1)
frame_1.Show()
app.MainLoop()
Другие советы
Вы можете попробовать EVT_LIST_ITEM_RIGHT_CLICK. Это должно работать. В противном случае вы хотите использовать флаг и проверять указанный флаг каждый раз, когда события выбора стреляются, чтобы увидеть, нужно ли запрашивать базу данных или нет. Есть также UltimatelistCTRL, чистый виджет Python, который вы, вероятно, можете взломать это тоже.
Вы можете нажать на пользовательский обработчик событий
import wx
class MyEventHandler(wx.PyEvtHandler):
def __init__(self,target):
self.target = target
wx.PyEvtHandler.__init__(self)
def ProcessEvent(self,event):
# there must be a better way of getting the event type,
# but I couldn't find it
if event.GetEventType() == wx.EVT_LEFT_DOWN.evtType[0]:
print "Got Mouse Down event"
(item,where) = self.target.HitTest(event.GetPosition())
if item != -1:
print self.target.GetItem(item,0).GetText()
print where
else:
print "Not on list item though"
return True
else:
return False
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.list_ctrl_1 = wx.ListCtrl(self, -1, style=wx.LC_REPORT|wx.SUNKEN_BORDER)
self.myevthandler = MyEventHandler(self.list_ctrl_1)
sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
sizer_1.Add(self.list_ctrl_1, 1, wx.EXPAND, 0)
self.list_ctrl_1.InsertColumn(0,"1")
self.list_ctrl_1.InsertStringItem(0,"HELLO1")
self.list_ctrl_1.PushEventHandler(self.myevthandler)
if __name__ == "__main__":
app = wx.PySimpleApp(0)
wx.InitAllImageHandlers()
frame_1 = MyFrame(None, -1, "")
app.SetTopWindow(frame_1)
frame_1.Show()
app.MainLoop()