Deselection not part of a selection change in wxListCtrl Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Daniel Dekkers
Experienced Solver
Experienced Solver
Posts: 79
Joined: Wed Aug 15, 2012 8:04 am

Deselection not part of a selection change in wxListCtrl

Post by Daniel Dekkers »

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
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Deselection not part of a selection change in wxListCtrl

Post by doublemax »

Did you try checking the return value of wxListCtrl::GetSelectedItemCount() in both cases?
Use the source, Luke!
Daniel Dekkers
Experienced Solver
Experienced Solver
Posts: 79
Joined: Wed Aug 15, 2012 8:04 am

Re: Deselection not part of a selection change in wxListCtrl

Post by Daniel Dekkers »

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. :-(
Radek
Super wx Problem Solver
Super wx Problem Solver
Posts: 286
Joined: Sun Sep 11, 2011 7:17 am

Re: Deselection not part of a selection change in wxListCtrl

Post by Radek »

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.
Daniel Dekkers
Experienced Solver
Experienced Solver
Posts: 79
Joined: Wed Aug 15, 2012 8:04 am

Re: Deselection not part of a selection change in wxListCtrl

Post by Daniel Dekkers »

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 ;-)
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Deselection not part of a selection change in wxListCtrl

Post by doublemax »

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.
Use the source, Luke!
Daniel Dekkers
Experienced Solver
Experienced Solver
Posts: 79
Joined: Wed Aug 15, 2012 8:04 am

Re: Deselection not part of a selection change in wxListCtrl

Post by Daniel Dekkers »

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.
Attachments
Deselect.png
Deselect.png (20.8 KiB) Viewed 4799 times
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Deselection not part of a selection change in wxListCtrl

Post by doublemax »

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.
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".
Use the source, Luke!
Radek
Super wx Problem Solver
Super wx Problem Solver
Posts: 286
Joined: Sun Sep 11, 2011 7:17 am

Re: Deselection not part of a selection change in wxListCtrl

Post by Radek »

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.
Daniel Dekkers
Experienced Solver
Experienced Solver
Posts: 79
Joined: Wed Aug 15, 2012 8:04 am

Re: Deselection not part of a selection change in wxListCtrl

Post by Daniel Dekkers »

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?
Daniel Dekkers
Experienced Solver
Experienced Solver
Posts: 79
Joined: Wed Aug 15, 2012 8:04 am

Re: Deselection not part of a selection change in wxListCtrl

Post by Daniel Dekkers »

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.

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;
	}
}
and...

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;
	}
}
Post Reply