문제

I'm working on a form using wxPython where I want want listctrl's list of values to change based on the selection of another listctrl. To do this, I'm using methods linked to the controlling object's EVT_LIST_ITEM_SELECTED and EVT_LIST_ITEM_DESELECTED events to call Publisher.sendMessage. The control to be changed has a method that is a subscriber to that publisher. This works: when the first listctrl is clicked, the second is refreshed.

The problem is that the data must be refreshed from the database and a message is sent for every selection and deselection. This means that even if I simply click on one item, the database gets queried twice (once for the deselection, then again for the selection). If I shift-click to multi-select 5 items, then 5 calls get made. Is there any way to have the listctrl respond to the set, rather than the individual selections?

도움이 되었습니까?

해결책

The best solution seems to be to use wx.CallAfter with a flag to execute the follow-up procedure exactly once:

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()

다른 팁

You can try EVT_LIST_ITEM_RIGHT_CLICK. That should work. Otherwise you'd want to use a flag and check said flag every time the selection event fires to see if it needs to query the database or not. There's also the UltimateListCtrl, a pure python widget, that you can probably hack to do this too.

You can push in a custom event handler

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()
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top