Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

HELP! stopping selection in a CListCtrl

394 views
Skip to first unread message

James Chow

unread,
Nov 6, 1999, 3:00:00 AM11/6/99
to
Hi all.

I have a number of items with a number of associated
"properties" and they are represented using a single-selection
CListCtrl.

When the user makes a selection, these properties are checked
to see whether they are all valid. If any of these properties
are invalid, the user is given the option to validate them.
Should he/she wish not to validate, the selection is reverted
to the original.

The problem, I am getting is that, when the user decides not
to validate, Windows sends another notification message. This
causes problems as it performs the validation again and brings
up the message box asking the user for validation.

How do I stop this?

Also, I'm using the LVN_ITEMCHANGED message. I've tried using
the LVN_ITEMCHANGING message (with a few tweaks as item wouldn't
have been selected yet) but I still have the same problem.

TIA,
j.


example test code snippet...

ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, OnItemchangedList1)

BOOL CMfctestDlg::CheckValid(int idx)
{
//a dummy test, the fourth is invalid
if (idx == 3)
return FALSE;
return TRUE;
}

void CMfctestDlg::OnItemchangedList1(NMHDR * pNMHDR,
LRESULT * pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

int idx = m_listCtrl.GetNextItem(-1, LVNI_SELECTED);
BOOL bRevert = FALSE;

if (CheckValid(idx) == FALSE)
{
OutputDebugString("have properties invalid\n");
BOOL bRC = AfxMessageBox("have properties invalid.\n"\
"click ok to list properties.",
MB_OKCANCEL);
if (bRC == IDOK)
{
OutputDebugString("listing properties\n");
bRC = AfxMessageBox("list of properties...\n"\
"click ok to validate properties.",
MB_OKCANCEL);
if (bRC == IDOK)
{
OutputDebugString("properties validated\n");
//properties validated, nothing to do
}
else
{
OutputDebugString("properties not validated\n");
bRevert = TRUE;
}
}
else
{
OutputDebugString("not listing properties\n");
bRevert = TRUE;
}
}

if (bRevert == TRUE)
{
m_listCtrl.SetItem(0, 0, LVIF_STATE, NULL, 0,
LVIS_SELECTED | LVIS_FOCUSED,
LVIS_SELECTED | LVIS_FOCUSED, NULL);
}

*pResult = 0;
}


--
James Chow

Chip Calvert

unread,
Nov 9, 1999, 3:00:00 AM11/9/99
to
On Sat, 6 Nov 1999 19:22:40 +0000, James Chow
<ja...@chowfam.demon.co.uk> wrote:

>Hi all.
>
>I have a number of items with a number of associated
>"properties" and they are represented using a single-selection
>CListCtrl.
>
>When the user makes a selection, these properties are checked
>to see whether they are all valid. If any of these properties
>are invalid, the user is given the option to validate them.
>Should he/she wish not to validate, the selection is reverted
>to the original.
>
>The problem, I am getting is that, when the user decides not
>to validate, Windows sends another notification message. This
>causes problems as it performs the validation again and brings
>up the message box asking the user for validation.

The trick is to use the information passed to the message handler to
determine whether or not the item in question is being selected. See
below.

It is also important to realize that when a new item is selected, this
event will be generated twice: once for the item that was previously
selected (and is now deselected) and once for the newly selected item.

>How do I stop this?
>
>Also, I'm using the LVN_ITEMCHANGED message. I've tried using
>the LVN_ITEMCHANGING message (with a few tweaks as item wouldn't
>have been selected yet) but I still have the same problem.
>
>TIA,
>j.
>
>
>example test code snippet...
>
>ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, OnItemchangedList1)
>
>BOOL CMfctestDlg::CheckValid(int idx)
>{
> //a dummy test, the fourth is invalid
> if (idx == 3)
> return FALSE;
> return TRUE;
>}
>
>void CMfctestDlg::OnItemchangedList1(NMHDR * pNMHDR,
> LRESULT * pResult)
>{
> NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
>
> int idx = m_listCtrl.GetNextItem(-1, LVNI_SELECTED);

Don't do this. The NM_LISTVIEW struct contains all you need. From
the docs:

typedef struct tagNM_LISTVIEW {
NMHDR hdr;
int iItem;
int iSubItem;
UINT uNewState;
UINT uOldState;
UINT uChanged;
POINT ptAction;
LPARAM lParam;
} NM_LISTVIEW;

In this structure the items you care about are:

iItem: Identifies the list view item, or -1 if not used.

uNewState: Specifies the new item state. This member is zero for
notification messages that do not use it.

uOldState: Specifies the old item state. This member is zero for
notification messages that do not use it.


When you get the message, see if uNewState | LVS_SELECTED is true. If
so, the item is being selected and can be validated.

If not, check if uOldState | LVS_SELECTED is true. If so, then
pNMListView->iItem is the index of the item that is being deselected.
Store it so that you can change the selection back if necessary.


--
Chip
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
"Make it idiot-proof and someone will make a better idiot."
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Chip Calvert

unread,
Nov 10, 1999, 3:00:00 AM11/10/99
to
On Tue, 09 Nov 1999 19:35:23 -0500, Chip Calvert <cb...@yahoo.com>
wrote:

>When you get the message, see if uNewState | LVS_SELECTED is true.

That should be uNewState & LVS_SELECTED.

>If not, check if uOldState | LVS_SELECTED is true.

This should be uOldState & LVS_SELECTED.

Sorry!

wavey...@gmail.com

unread,
Nov 27, 2012, 8:39:31 PM11/27/12
to
To deal with a multi-select CListCtrl, it is likely better to focus on the LVIS_FOCUSED state rather than LVIS_SELECTED state (pun intended). For validation, you want to use the LVN_ITEMCHANGING event rather than the LVN_ITEMCHANGED event.

So the validation check is only done on the condition of losing focus:
// Process this message
if ((pNMLV->uOldState & LVIS_FOCUSED) && !(pNMLV->uNewState & LVIS_FOCUSED))
{
// Validate
// ...
}

Further, when needing to validate and cancel the change to the new item, you'll need to not only explicitly revert the state but also set *pResult to non-zero so the code looks like:

if (bRevert == TRUE)
{
m_listCtrl.SetItemState(pNMLV->iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
*pResult = 1;
return;
}

All this being said...after returning here the LVN_ITEMCHANGING event is still received a second time! In this case, the pNMLV->iItem is the same value. Why is this happening?! Here is the results of outputting the state when the first element (i.e. iItem=0) is selected, validated, and prevented from switching:

LVN_ITEMCHANGING, iItem=0, uChanged=8, uOldState=2, uNewState=0
LVN_ITEMCHANGED, iItem=0, uChanged=8, uOldState=2, uNewState=0
LVN_ITEMCHANGING, iItem=0, uChanged=8, uOldState=1, uNewState=0
<< Catch this pending state change here...prompt user...user cancels, CListCtrl::SetItemState() is called setting LVIS_SELECTED | LVIS_FOCUSED, and *pResult set to 1.>>
LVN_ITEMCHANGING, iItem=0, uChanged=8, uOldState=1, uNewState=3
LVN_ITEMCHANGED, iItem=0, uChanged=8, uOldState=1, uNewState=3
LVN_ITEMCHANGING, iItem=0, uChanged=8, uOldState=1, uNewState=0
<< Why is this being hit a second time?!? >>
LVN_ITEMCHANGINGm, iItem=0, uChanged=8, uOldState=3, uNewState=3

Can anyone offer any insight?

David

PS: 13 years later...but still using this stuff! Bump!
PPS: Just found this nice little summary here, although it doesn't answer this specific question may likely be useful for [novice] users of CListCtrl should they stumble on this thread:
http://www.celticwolf.com/useful-information/faqs/10-clistctrl-faq
0 new messages