Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. OnItemChanged runs several times!

OnItemChanged runs several times!

Scheduled Pinned Locked Moved C / C++ / MFC
debuggingdatabasedesignhelp
6 Posts 3 Posters 2 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • N Offline
    N Offline
    ns
    wrote on last edited by
    #1

    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

    J M 2 Replies Last reply
    0
    • N 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

      J Offline
      J Offline
      Joan M
      wrote on last edited by
      #2

      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...

      N 1 Reply Last reply
      0
      • N 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

        M Offline
        M Offline
        Mike Upton
        wrote on last edited by
        #3

        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)

        N 1 Reply Last reply
        0
        • J Joan M

          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...

          N Offline
          N Offline
          ns
          wrote on last edited by
          #4

          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

          1 Reply Last reply
          0
          • M Mike Upton

            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)

            N Offline
            N Offline
            ns
            wrote on last edited by
            #5

            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

            M 1 Reply Last reply
            0
            • N 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

              M Offline
              M Offline
              Mike Upton
              wrote on last edited by
              #6

              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)

              1 Reply Last reply
              0
              Reply
              • Reply as topic
              Log in to reply
              • Oldest to Newest
              • Newest to Oldest
              • Most Votes


              • Login

              • Don't have an account? Register

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • World
              • Users
              • Groups