Deselection not part of a selection change in wxListCtrl Topic is solved
-
- Experienced Solver
- Posts: 79
- Joined: Wed Aug 15, 2012 8:04 am
Deselection not part of a selection change in wxListCtrl
Hi,
I have a (single selection) wxListCtrl and would like to distinguish the case where a current selection is deselected, but is not "just" changing to another entry.
For instance when the user clicks in the wxListCtrl outside the region containing actual entries. The selection is then removed, leaving zero selected entries.
I can catch wxEVT_COMMAND_LIST_ITEM_DESELECTED of course, but this is also (correctly) sent when the current selection is changing to a new entry.
Is there some way I can see (for instance in the event fired with wxEVT_COMMAND_LIST_ITEM_DESELECTED) if the deselection is a "real" deselection or part of a selection change?
Thanks,
Daniel Dekkers
I have a (single selection) wxListCtrl and would like to distinguish the case where a current selection is deselected, but is not "just" changing to another entry.
For instance when the user clicks in the wxListCtrl outside the region containing actual entries. The selection is then removed, leaving zero selected entries.
I can catch wxEVT_COMMAND_LIST_ITEM_DESELECTED of course, but this is also (correctly) sent when the current selection is changing to a new entry.
Is there some way I can see (for instance in the event fired with wxEVT_COMMAND_LIST_ITEM_DESELECTED) if the deselection is a "real" deselection or part of a selection change?
Thanks,
Daniel Dekkers
Re: Deselection not part of a selection change in wxListCtrl
Did you try checking the return value of wxListCtrl::GetSelectedItemCount() in both cases?
Use the source, Luke!
-
- Experienced Solver
- Posts: 79
- Joined: Wed Aug 15, 2012 8:04 am
Re: Deselection not part of a selection change in wxListCtrl
Yes, it will always be 0 (which is correct, for a (brief) moment there are no selections in both cases).
So that won't help a lot.
So that won't help a lot.
Re: Deselection not part of a selection change in wxListCtrl
IMO, the same problem as with "double click". First, you get a "single click" and then a "double click" if it was really a double click. You cannot decide at the "single click" whether it is a double click or not. Similarly, at deselect event you cannot see whether it is a real deselect or just a switch to another item.
I've never solved this kind of problems but, IMO, you get the "select" event short after a deselect one when it is a switch. Start a short "one shot" timer from the "deselect" event and set a flag from the "select" event. Process the selection when the timer expires. If the flag is set, it was a switch. If it isn't set then it was a real deselection. I would do something like this when I would need to distinguish between "single click" and "double click" when I couldn't act at single click time.
I've never solved this kind of problems but, IMO, you get the "select" event short after a deselect one when it is a switch. Start a short "one shot" timer from the "deselect" event and set a flag from the "select" event. Process the selection when the timer expires. If the flag is set, it was a switch. If it isn't set then it was a real deselection. I would do something like this when I would need to distinguish between "single click" and "double click" when I couldn't act at single click time.
-
- Experienced Solver
- Posts: 79
- Joined: Wed Aug 15, 2012 8:04 am
Re: Deselection not part of a selection change in wxListCtrl
Yeah, I thought about the timer, but... -blech-
IMO it's not really the same as doubleclick because in this case wxWidgets knows if it is a deselection because of a change event or not.
For wxWidgets, the first trigger is the new selection, which will probably be implemented as "fire deselect old event"; "fire select new event";.
wxTreeCtrl does has separate EVT_TREE_SEL_CHANGING and EVT_TREE_SEL_CHANGED events.
But I'm not sure if EVT_TREE_SEL_CHANGING in wxTreeCtrl is also sent when deselecting an entry. Then you still wouldn't know.
For doubleclick the timer is correct and unavoidable, i think it is even a OS parameter in Windows that you can change, for fast double clickers and slow double clickers
IMO it's not really the same as doubleclick because in this case wxWidgets knows if it is a deselection because of a change event or not.
For wxWidgets, the first trigger is the new selection, which will probably be implemented as "fire deselect old event"; "fire select new event";.
wxTreeCtrl does has separate EVT_TREE_SEL_CHANGING and EVT_TREE_SEL_CHANGED events.
But I'm not sure if EVT_TREE_SEL_CHANGING in wxTreeCtrl is also sent when deselecting an entry. Then you still wouldn't know.
For doubleclick the timer is correct and unavoidable, i think it is even a OS parameter in Windows that you can change, for fast double clickers and slow double clickers
Re: Deselection not part of a selection change in wxListCtrl
Whatfor do you need this anyway?
If GetSelectedItemCount() is 0, can't you just perform your "no item selected" action in any case? If it's a deselect, nothing else will happen. If it's a "change selection", you'll get a ITEM_SELECTED event and you'll have to handle that anyway.
If GetSelectedItemCount() is 0, can't you just perform your "no item selected" action in any case? If it's a deselect, nothing else will happen. If it's a "change selection", you'll get a ITEM_SELECTED event and you'll have to handle that anyway.
Use the source, Luke!
-
- Experienced Solver
- Posts: 79
- Joined: Wed Aug 15, 2012 8:04 am
Re: Deselection not part of a selection change in wxListCtrl
I have a wxSplitterWindow with a wxListCtrl on the left and a panel on the right giving information about the selected item (see attach).
If the selection is removed altogether, the right panel should close ("unsplit" in wxSplitterWindow terminology).
But if the selection on the left is "just" changed to a new entry, I don't want to send two notifications, "close" (deselect old, unsplit) and "open with new selection" (select new, split) because it will create unnecessary flickering.
I don't fully understand your strategy using GetItemCount(). It will always be zero in the OnDeselect() handler (for single selection wxListCtrls), I don't think it will give any new information.
If the selection is removed altogether, the right panel should close ("unsplit" in wxSplitterWindow terminology).
But if the selection on the left is "just" changed to a new entry, I don't want to send two notifications, "close" (deselect old, unsplit) and "open with new selection" (select new, split) because it will create unnecessary flickering.
I don't fully understand your strategy using GetItemCount(). It will always be zero in the OnDeselect() handler (for single selection wxListCtrls), I don't think it will give any new information.
- Attachments
-
- Deselect.png (20.8 KiB) Viewed 4799 times
Re: Deselection not part of a selection change in wxListCtrl
Yes, you're right. I was thinking about a control with multiple selection. In that case i have no better idea than radek's "delayed action".I don't fully understand your strategy using GetItemCount(). It will always be zero in the OnDeselect() handler (for single selection wxListCtrls), I don't think it will give any new information.
Use the source, Luke!
Re: Deselection not part of a selection change in wxListCtrl
If you get the "select" event first then your problems are over. Set a flag at "select", process at "deselect". You could get the "select" event first: "select first, then deselect" is the correct way of suppressing flickering of a ribbon bar cursor dragged through a list of items, for example menus. But this means that you have selected multiple items temporarily. If the control isn't prepared for multiple selections then it must deselect first, then select.
You can avoid the timer most likely. The events we are speaking about are command events and they should be queued. When you get "deselect", post a custom "process now" event to yourself. You should get your custom event after both "select" and "deselect" actions so that the "process now" handler can distinguish between switching items and real deselections. Possible problem: you get "deselect" event prior wxWidgets posts the "select" event during an item switch. You need experimenting.
As far as "item is changing" kind of events is concerned, these events are sent and they are testing for veto primarily. They aren't directly related to selection and deselection actions.
You can avoid the timer most likely. The events we are speaking about are command events and they should be queued. When you get "deselect", post a custom "process now" event to yourself. You should get your custom event after both "select" and "deselect" actions so that the "process now" handler can distinguish between switching items and real deselections. Possible problem: you get "deselect" event prior wxWidgets posts the "select" event during an item switch. You need experimenting.
As far as "item is changing" kind of events is concerned, these events are sent and they are testing for veto primarily. They aren't directly related to selection and deselection actions.
-
- Experienced Solver
- Posts: 79
- Joined: Wed Aug 15, 2012 8:04 am
Re: Deselection not part of a selection change in wxListCtrl
Yes, the problem is that the deselect event is always fired first.
So, for the wxListCtrl, two scenarios:
1) A change...
OnDeselect(...) {event contains entry deselected (the old entry)}
OnSelect(...) {event contains entry selected (the new entry)}
2) A "real" deselect...
OnDeselect(...) {event represents item deselected}
Setting a flag in OnSelect() would be "too late" when it turns out to be scenario 1. And if it turns out to be scenario 2, action should be taken in OnDeselect(...), not just setting a flag (which would never be read anyway).
Are you suggesting that in scenario 1, when the OnDeselect(...) is called the selection event is already in a queue somehow? Is there any way I could look ahead in that queue?
So, for the wxListCtrl, two scenarios:
1) A change...
OnDeselect(...) {event contains entry deselected (the old entry)}
OnSelect(...) {event contains entry selected (the new entry)}
2) A "real" deselect...
OnDeselect(...) {event represents item deselected}
Setting a flag in OnSelect() would be "too late" when it turns out to be scenario 1. And if it turns out to be scenario 2, action should be taken in OnDeselect(...), not just setting a flag (which would never be read anyway).
Are you suggesting that in scenario 1, when the OnDeselect(...) is called the selection event is already in a queue somehow? Is there any way I could look ahead in that queue?
-
- Experienced Solver
- Posts: 79
- Joined: Wed Aug 15, 2012 8:04 am
Re: Deselection not part of a selection change in wxListCtrl
Ok, fixed it, maybe not the beauty prize, but it works.
I postpone the first deselection by GetEventHandler()->AddPendingEvent(p_Event) which gives the order OnSelected(), OnDeselected() that we need.
Maybe I could clear the event queue with DeletePendingEvents() in OnSelected(), avoiding the second call of OnDeselected() but I find deleting event queues a bit dangerous.
Thanks for helping.
and...
I postpone the first deselection by GetEventHandler()->AddPendingEvent(p_Event) which gives the order OnSelected(), OnDeselected() that we need.
Maybe I could clear the event queue with DeletePendingEvents() in OnSelected(), avoiding the second call of OnDeselected() but I find deleting event queues a bit dangerous.
Thanks for helping.
Code: Select all
void
c_ItemListListView::OnSelected(wxCommandEvent& p_Event)
{
// Called when the user has made a new selection...
int l_NewIndex = wxListView::GetFirstSelected(); // This is the new index...
if (l_NewIndex!=wxNOT_FOUND)
{
c_Item* l_NewItem = m_ItemListModel->GetNthItem(l_NewIndex);
m_ItemListModel->NotifyViews(c_Model::e_SelectionChanged, (void*) l_NewItem);
m_PendingDeselection = false;
}
}
Code: Select all
void
c_ItemListListView::OnDeselected(wxListEvent& p_Event)
{
// This event is fired when a selection changes but also when an item is deselected, for instance,
// by clicking in the region of the wxListCtrl not containing any entries. To distinguish these two cases
// and not send two notifications we postpone this event and give OnSelected() a chance to intercept.
int l_Index = p_Event.GetIndex();
if (m_PendingDeselectedItem==NULL)
{
// Postpone this event, so OnSelected() gets a chance to select first...
m_PendingDeselectedItem = m_ItemListModel->GetNthItem(l_Index);
m_PendingDeselection = true;
GetEventHandler()->AddPendingEvent(p_Event);
}
else
{
if (m_PendingDeselection)
{
// We "really" have to deselect...
m_ItemListModel->NotifyViews(c_Model::e_SelectionChanged, (void*) NULL);
}
m_PendingDeselectedItem = NULL;
m_PendingDeselection = false;
}
}