Search code examples
c++loopsmfctreecontrol

MFC tree control notification is triggered twice


My problem is that the following function is called twice:

ON_NOTIFY(TVN_SELCHANGED, IDC_TREE1, &MainHamsterDlg::OnClickTree)

void MainHamsterDlg::OnClickTree(NMHDR* pNMHDR, LRESULT* pResult)
{
    CTreeCtrl* pCtrl = (CTreeCtrl*)GetDlgItem(IDC_TREE1);
    HTREEITEM hItem = pCtrl->GetSelectedItem();
    BOOL hItemm = pCtrl->ItemHasChildren(hItem);
    if (hItem && hItemm)
    {
        HTREEITEM hChild = pCtrl->GetChildItem(hItem);
        pCtrl->SelectItem(hChild);                           <--- Cause of the "loop"
    }

    *pResult = 1;
}

I need my code to automatically go to a child element of the tree. (In future I will write some code to detect what has been selected and it will cause some actions.)

My code works correctly when I click on a leaf, because:

if (hItem && hItemm)

ensures that:

pCtrl->SelectItem(hChild);

won't be executed. How can I make my code work when an internal node is clicked?


Solution

  • I know this is a dirty hack, but it should prevent your code from being executed twice. Add the following member to your class:

    bool ignoreNextSelChange = false;
    

    Then modify your function as follows:

    void MainHamsterDlg::OnClickTree(NMHDR* pNMHDR, LRESULT* pResult)
    {
        if (ignoreNextSelChange)
        {
            // Don't do anything, but make sure that the else block below will be executed
            // again with the next (expected) call of this function.
            ignoreNextSelChange = false;
        }
        else
        {
            CTreeCtrl* pCtrl = (CTreeCtrl*)GetDlgItem(IDC_TREE1);
            HTREEITEM hItem = pCtrl->GetSelectedItem();
            BOOL hItemm = pCtrl->ItemHasChildren(hItem);
            if (hItem && hItemm)
            {
                HTREEITEM hChild = pCtrl->GetChildItem(hItem);
    
                // Make sure that this else block won't be executed again when the function
                // SelectItem() is called below.
                ignoreNextSelChange = true;
    
                pCtrl->SelectItem(hChild);
            }
        }
        *pResult = 1;
    }