OnItemChanged runs several times!
-
If I put a breakpoint in OnItemChanged of my CListCtrl, and debug, it runs through the function many many times! The statement at which I step into this function is a SetItemState to highlight a previous element.At first I thought it ran only twice, so I put a boolean flag which returned the code right away at the second pass after setting it to false again (the first time it runs, this flag is set to true at the end of the function....). However OnItem runs over and over again, setting and unsetting the flag:
OnItemChanged()
{
if (flag)
{
flag = false;
return
}if (some condition)
{
AfxMessageBox(...);
flag = true;
list1.SetItemState(....);
// this line seems to trigger the onitemchanged recursively.....despite the flag,
return;
}so I alternate between getting the messagebox and not in pairs of runs. Funnily enough after a zillion times of doing this it suddenly goes through like it should and the UI shows again, with the highlight where I intended it to be. My intention was to have the messagebox pop up only once, and when dismissed the highlight should have been on the desired item and the UI ready for the next move. } Appreciate your help, ns
-
If I put a breakpoint in OnItemChanged of my CListCtrl, and debug, it runs through the function many many times! The statement at which I step into this function is a SetItemState to highlight a previous element.At first I thought it ran only twice, so I put a boolean flag which returned the code right away at the second pass after setting it to false again (the first time it runs, this flag is set to true at the end of the function....). However OnItem runs over and over again, setting and unsetting the flag:
OnItemChanged()
{
if (flag)
{
flag = false;
return
}if (some condition)
{
AfxMessageBox(...);
flag = true;
list1.SetItemState(....);
// this line seems to trigger the onitemchanged recursively.....despite the flag,
return;
}so I alternate between getting the messagebox and not in pairs of runs. Funnily enough after a zillion times of doing this it suddenly goes through like it should and the UI shows again, with the highlight where I intended it to be. My intention was to have the messagebox pop up only once, and when dismissed the highlight should have been on the desired item and the UI ready for the next move. } Appreciate your help, ns
This function gets called when a item receives the focus, when a item loses the focus, when a item is selected... I filter that using this code:
void CPPDlgParametritzacions::OnItemchangedLctrlIntroduccio(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;// if the item is not the same that was selected before and there's one item to process... if ((pNMListView->iItem != this->m\_iElementSeleccionatAnt) && (pNMListView->iItem != -1)) { // remember which item has been selected in a member var of the dialog class that holds the listCtrl, you can also derive a listctrl and make this internally... this->m\_iElementSeleccionatAnt = pNMListView->iItem; // depending on the selected state of the current item... if (this->m\_cLCtrlParametritzacions.GetItemState(pNMListView->iItem, LVIS\_SELECTED) == LVIS\_SELECTED) {
hope this helps...
-
If I put a breakpoint in OnItemChanged of my CListCtrl, and debug, it runs through the function many many times! The statement at which I step into this function is a SetItemState to highlight a previous element.At first I thought it ran only twice, so I put a boolean flag which returned the code right away at the second pass after setting it to false again (the first time it runs, this flag is set to true at the end of the function....). However OnItem runs over and over again, setting and unsetting the flag:
OnItemChanged()
{
if (flag)
{
flag = false;
return
}if (some condition)
{
AfxMessageBox(...);
flag = true;
list1.SetItemState(....);
// this line seems to trigger the onitemchanged recursively.....despite the flag,
return;
}so I alternate between getting the messagebox and not in pairs of runs. Funnily enough after a zillion times of doing this it suddenly goes through like it should and the UI shows again, with the highlight where I intended it to be. My intention was to have the messagebox pop up only once, and when dismissed the highlight should have been on the desired item and the UI ready for the next move. } Appreciate your help, ns
SetItemState might well be triggering several OnItemChanged calls - especially if you're changing the selection, because it might (depends if you've got multi-select enabled) unselect one item before selecting the next. Anyway, whatever is going on, the easy solution is to set your flag before your call to SetItemState, and unset the flag when the call to SetItemState has returned:
::OnItemChanged(...) {
static bool flag = false;
if (flag) return;... if (some condition) { flag = true; //lock-out OnItemChanged list1.SetItemState(...); flag = false; //re-enable OnItemChanged } ...
}
"We are the knights who say Ni" (The Knights Who Say Ni)
-
This function gets called when a item receives the focus, when a item loses the focus, when a item is selected... I filter that using this code:
void CPPDlgParametritzacions::OnItemchangedLctrlIntroduccio(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;// if the item is not the same that was selected before and there's one item to process... if ((pNMListView->iItem != this->m\_iElementSeleccionatAnt) && (pNMListView->iItem != -1)) { // remember which item has been selected in a member var of the dialog class that holds the listCtrl, you can also derive a listctrl and make this internally... this->m\_iElementSeleccionatAnt = pNMListView->iItem; // depending on the selected state of the current item... if (this->m\_cLCtrlParametritzacions.GetItemState(pNMListView->iItem, LVIS\_SELECTED) == LVIS\_SELECTED) {
hope this helps...
Thanks. I'll work on your suggestion. Why this is happpening is because I am forcing the selection back to the one is was on, i nstead of the newly selected one, and I am doing this in the OnItemChanged....thats why it runs 4 times.... Appreciate your help, ns
-
SetItemState might well be triggering several OnItemChanged calls - especially if you're changing the selection, because it might (depends if you've got multi-select enabled) unselect one item before selecting the next. Anyway, whatever is going on, the easy solution is to set your flag before your call to SetItemState, and unset the flag when the call to SetItemState has returned:
::OnItemChanged(...) {
static bool flag = false;
if (flag) return;... if (some condition) { flag = true; //lock-out OnItemChanged list1.SetItemState(...); flag = false; //re-enable OnItemChanged } ...
}
"We are the knights who say Ni" (The Knights Who Say Ni)
Thanks. In my pretranslatemsg, i trap enter for a text box. If I dont like the user entry I return right away. If I accept it, then I go ahead and move my selection in an adjacent listctrl ahead by one ....using SetItemState(++m_index..) WIth this happening ,in this function your lock-unlock works great. However I also have the case where the user puts in a bad entry in the textbox and tries to advance to a new selection in the listbox. OnItem runs of course. In this I check to see if I like the entry . If I dont I want to force the selection to remain where it is, not move the one I just clicked on. Again I do SetItemState....this time in OnItemChanged. However now the unlock-lock trick doesnt work because oddly , after it goes through the first two times, lock setItem runs onitem unlock runs onitem and returns as it should onitem runs yet again! but my flags all restored so it goes through all over again. Thanks for the help again, it then does another pair.............probably because it was trying to go to the new one and I forced it back or something. ns
-
Thanks. In my pretranslatemsg, i trap enter for a text box. If I dont like the user entry I return right away. If I accept it, then I go ahead and move my selection in an adjacent listctrl ahead by one ....using SetItemState(++m_index..) WIth this happening ,in this function your lock-unlock works great. However I also have the case where the user puts in a bad entry in the textbox and tries to advance to a new selection in the listbox. OnItem runs of course. In this I check to see if I like the entry . If I dont I want to force the selection to remain where it is, not move the one I just clicked on. Again I do SetItemState....this time in OnItemChanged. However now the unlock-lock trick doesnt work because oddly , after it goes through the first two times, lock setItem runs onitem unlock runs onitem and returns as it should onitem runs yet again! but my flags all restored so it goes through all over again. Thanks for the help again, it then does another pair.............probably because it was trying to go to the new one and I forced it back or something. ns
Have you tried handling LVN_ITEMCHANGING instead, and returning FALSE to prevent the change (see MSDN for LVN_ITEMCHANGING). I haven't tried this myself, so I don't know if it works. Your other option is to keep track of the currently selected item in a member variable, and only processing the ItemChanged notification if it's trying to select a different item to the one you think is currently selected.
YourClass::OnItemChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
NMLISTVIEW* pNMLV = reinterpret_cast(pNMHDR);
//assuming you're only interested in the new selection, so check
//whether the LVIS_SELECTED state is set
if (!(pNMLV->uNewState & LVIS_SELECTED)) return;//Make sure m\_CurrentSelection is initialised in the constructor to //an invalid value like -1, so that this works for the first selection. //This checks that we're not just resetting the selection back to the //current one. if (pNMLV->iItem == m\_CurrentSelection) return; if (whatever\_condition\_your\_checking\_is\_okay) { //allow the new selection m\_CurrentSelection = pNMLV->iItem; } else { //go back to the old selection m\_List.SetItemState(m\_CurrentSelection, LVIS\_SELECTED, LVIS\_SELECTED); }
}
N.B. Untested code - it's just an example of what I mean.
"We are the knights who say Ni" (The Knights Who Say Ni)