wx.ListCtrl: telling a user's Click from program's a_listctrl.Select()
A first question post to SO.
When a user clicks on a ListCtrl widget it generates a EVT_LIST_ITEM_SELECTED event. However if I want set up the list before display to the user so that several items are already highlighted (by calling Select() on the ListCtrl) the widget generates the same event. This event is the incorrectly processed by my application as if it were a real user selection.
As wxPython uses message passing I cannot simply set a flag (ignore_selection_events) before I do my programatic selections and then clear it afterward. As in all likelyhood the flag will have been cleared before the first EVT_LIST_ITEM_SELECTED handler/call-back is invoked.
Some solutions I tried and what went wrong:
There is a member of ListCtrl that allows turning off generation of the EVT_LIST_ITEM_SELECTED. I've looked and I'm sure this does not exist.
I can use a wx.Timer to delay the unsetting the ignore_selection_event flag for a time after the last call to Select(). The exact timing is error prone. It may not work (time too short) or may cause a real user selection to get lost (timer too long).
It should be possible using PostEvent or ProcessEvent to get the ListCtrl to generate a special ignore_selections event before the generating the first EVT_LIST_ITEM_SELECTED and an开发者_StackOverflow社区other after the last. I tried this but the call backs for the ignore event message are not called in the order I expected:
evt = MyEvent(myEVT_TOGGLE_SELECTION_IGNORE) wx.PostEvent(self.list_ctl, evt) //this handler called fist wx.CallAfter (self.list_ctl.Select, item, 1) //this handler called last (grrr) evt = MyEvent(myEVT_TOGGLE_SELECTION_IGNORE) wx.PostEvent(self.list_ctl, evt) //this handler called second
Finally I just had the idea of temporarily unbinding the event handler for EVT_LIST_ITEM_SELECTED. This will probably suffer from the same problem as using the flag. I.e. the handler will be replaced before wxPython gets around to asynchronously handling the Select() calls and so will still invoke the handler. Just tried this and it causes the gui to immediately hang. I tried using
self.list_ctl.Bind(wx.EVT_LIST_ITEM_SELECTED, do_nothing)
but with a without CallAfter and in both cases the gui would immediately hang.
Okay over to you SO!
UPDATE:
Thanks Jeff! Some more info based on what I tried.
list_ctrl.SetItemState(item_index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) #works
list_ctrl.SetItemState(item_index, 0xFFFFFFFF, wx.LIST_STATE_SELECTED) #works
list_ctrl.SetItemState(item_index, 1, wx.LIST_STATE_SELECTED) # does NOT work
So the use of both the state and mask args is so that you can easily modify the item state without having to first read the current state, OR in the required modification bits and then write back.
Try SetItemState
. I use the following in my code to deselect an item:
self.ballotC.SetItemState(c, 0, wx.LIST_STATE_SELECTED)
I would try
self.ballotC.SetItemState(c, 1, wx.LIST_STATE_SELECTED)
or
self.ballotC.SetItemState(c, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
to select an item. There is some documentation here. It isn't as clear as it could be so you have to play around a bit until you get it right.
精彩评论