Répondre au changement Listctrl exactement une fois
Question
Je travaille sur un formulaire en utilisant wxPython où je veux la liste des valeurs besoin listctrl changer en fonction de la sélection d'un autre listctrl. Pour ce faire, je suis en utilisant des méthodes liées à l'EVT_LIST_ITEM_SELECTED
de l'objet de contrôle et les événements EVT_LIST_ITEM_DESELECTED
à l'appel Publisher.sendMessage
. Le contrôle à modifier a une méthode qui est un abonné à cet éditeur. Cela fonctionne. Lorsque le premier listctrl est cliqué, le second est rafraîchi
Le problème est que les données doivent être mises à jour de la base de données et un message est envoyé pour chaque désélection et sélection. Cela signifie que même si je vous suffit de cliquer sur un élément, la base de données est deux fois interrogés (une fois pour la désélection, puis de nouveau pour la sélection). Si je touche Maj enfoncée pour sélectionner plusieurs éléments 5, puis 5 appels sont faits. Est-il possible d'avoir la listctrl répondent à l'ensemble, plutôt que les sélections individuelles?
La solution
La meilleure solution semble être d'utiliser wx.CallAfter
avec un drapeau pour exécuter exactement une fois la procédure de suivi:
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()
Autres conseils
Vous pouvez essayer EVT_LIST_ITEM_RIGHT_CLICK. Cela devrait fonctionner. Sinon, vous voudriez utiliser un drapeau et vérifier ledit drapeau chaque fois que l'événement se déclenche de sélection pour voir si elle a besoin d'interroger la base de données ou non. Il y a aussi le UltimateListCtrl, un widget pur python, que vous pouvez probablement pirater le faire aussi.
Vous pouvez pousser dans un gestionnaire d'événements personnalisé
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()