Responder a los cambios Listctrl exactamente una vez
Pregunta
Estoy trabajando en un formulario utilizando wxPython donde quiero lista de falta de listctrl de los valores a cambios basados ??en la selección de otro listctrl. Para hacer esto, estoy usando métodos vinculados a acontecimientos EVT_LIST_ITEM_SELECTED
y EVT_LIST_ITEM_DESELECTED
del objeto de control a Publisher.sendMessage
llamada. El control que ser cambiado tiene un método que es un abonado al que el editor. Estos trabajos:. Cuando se hace clic la primera listctrl, el segundo se actualiza
El problema es que los datos se deben actualizar la base de datos y se envía un mensaje para cada selección y deselección. Esto significa que incluso si simplemente hacer clic en un elemento, la base de datos consultadas consigue dos veces (una vez para la anulación de la selección, luego de nuevo para la selección). Si la tecla Mayús para seleccionar varios artículos 5, a continuación, 5 llamadas se envían. ¿Hay alguna manera de recibir la respuesta del listctrl al conjunto, en lugar de las selecciones individuales?
Solución
La mejor solución parece ser el uso de wx.CallAfter
con una bandera para ejecutar el procedimiento de seguimiento exactamente una vez:
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()
Otros consejos
Puede intentar EVT_LIST_ITEM_RIGHT_CLICK. Eso debería funcionar. De lo contrario, querrá usar una bandera y comprobar dicho indicador cada vez que se activa el evento de selección para ver si se necesita consultar la base de datos o no. También existe la UltimateListCtrl, un widget pura pitón, que es probable que pueda piratear a hacer esto también.
Se puede empujar en un controlador de eventos personalizado
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()