الرد على تغيير ListCtrl بالضبط مرة واحدة
سؤال
أنا أعمل على نموذج باستخدام Wxpython حيث أريد تغيير قائمة القيم التي يجب تغييرها بناءً على اختيار ListCtrl آخر. للقيام بذلك ، أستخدم طرقًا مرتبطة بكائن التحكم EVT_LIST_ITEM_SELECTED
و EVT_LIST_ITEM_DESELECTED
أحداث للاتصال Publisher.sendMessage
. يحتوي التحكم الذي يجب تغييره على طريقة هي مشترك في هذا الناشر. هذا يعمل: عند النقر فوق ListCtrl الأول ، يتم تحديث الثاني.
المشكلة هي أنه يجب تحديث البيانات من قاعدة البيانات ويتم إرسال رسالة لكل اختيار وإزالة. هذا يعني أنه حتى إذا قمت ببساطة بالنقر فوق عنصر واحد ، يتم الاستعلام عن قاعدة البيانات مرتين (مرة واحدة لإزالة الإزالة ، ثم مرة أخرى للاختيار). إذا انقر فوق انقر إلى 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()