Link to home
Start Free TrialLog in
Avatar of arunykand
arunykandFlag for United States of America

asked on

CTreeCtrl Check Box

Hi...I have a dialog box with a tree control that has check-boxes in it.  What I need to do is, when any of the check-boxes in the tree control is checked, I need to do some processing, and for now let's just say, I need to put up a messagebox.  I added a function for the 'NM_CLICK' message to intercept the left button clicks in the tree control, then I do a 'GetCheck' to see if the button is checked.

When I check the box, the 'GetCheck' function returns a 0 but a checkmark appers in the box.  When I uncheck the box, the 'GetCheck' function returns a 1, and the checkmark is removed from the box.  So this isn't really helping me figure out when the box is checked and not.

Any help would be greatly appericated.

Here is my code for the 'NM_CLICK'

void CDirectoryCheckDlg::OnClickTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
  CPoint pt;
  GetCursorPos(&pt);
  m_testTree.ScreenToClient(&pt);
  UINT uFlags;

   HTREEITEM ht = m_testTree.HitTest(pt, &uFlags);
      
      if(ht != NULL)
      {
            // There is an item under the cursor.
            m_testTree.SelectItem(ht);

            // See what exactly was under the cursor:
            switch(uFlags)
            {
                  case TVHT_ONITEMSTATEICON:
                  {
                        // It is the icon (checkbox)
                        BOOL chkbox = m_testTree.GetCheck(ht);
                              if(chkbox)
                                    MessageBox("Button is checked");
                              
                                     //CString str;
                                    //str.Format("%d",chkbox);
                                   //MessageBox(str,NULL,NULL);
                        break;
                  }
                  case TVHT_ONITEMBUTTON:
                        // It is the button
                        break;

            }


      }



      *pResult = 0;
}
Avatar of mahesh1402
mahesh1402
Flag of India image

Something like following :

              UINT uFlags=0;
      HTREEITEM ht = m_testTree.HitTest(pt, &uFlags);

      if( uFlags & TVHT_ONITEMSTATEICON )
      {
            int iImage = GetItemState( ht, TVIS_STATEIMAGEMASK )>>12;
            SetItemState( ht, INDEXTOSTATEIMAGEMASK(iImage == 1 ? 2 : 1),TVIS_STATEIMAGEMASK );
      }

You may retrieve check state like this :

BOOL IsItemChecked(HTREEITEM hItem)
{
  return GetItemState( hItem, TVIS_STATEIMAGEMASK )>>12 == 2;
}

As per : http://www.codeguru.com/cpp/controls/treeview/misc-advanced/article.php/c663/

-MAHESH
Hi,

From MSDN :

>>When the user clicks the check box of a TreeView item, an NM_CLICK notification is sent to the parent window. When >>this occurs, the TVM_HITTEST message returns TVHT_ONITEMSTATEICON. The TreeView control uses this same >>condition to toggle the state of the check box.
>> Unfortunately, the TreeView control toggles the state after the NM_CLICK notification is sent.

>>You can post a user-defined message to the same window that is processing the NM_CLICK notification, and treat this >>user-defined message as a notification that the checked state has changed. Following is sample code that illustrates >>how this can be accomplished:

See Q261289: HOWTO: Know When the User Clicks a Check Box in a TreeView Control

The complete code is written.


Good luck!
Avatar of arunykand

ASKER

I am looking at the MSDN article from above and tried to duplicate the code, but can't get past the compile error for 'MapWindowPoints(HWND_DESKTOP, lpnmh->hwndFrom, &ht.pt, 1)';  error C2661: 'MapWindowPoints' : no overloaded function takes 4 parameters

BOOL CDirectoryCheckDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
      switch(wParam)
               {
            case WM_NOTIFY:
            {
                     LPNMHDR lpnmh = (LPNMHDR) lParam;
                     TVHITTESTINFO ht = {0};
                    
                     if((lpnmh->code  == NM_CLICK) && (lpnmh->idFrom == IDC_TREE1))
                     {
                          DWORD dwpos = GetMessagePos();

                          // include <windowsx.h> and <windows.h> header files
                          ht.pt.x = GET_X_LPARAM(dwpos);
                          ht.pt.y = GET_Y_LPARAM(dwpos);
                          MapWindowPoints(HWND_DESKTOP, lpnmh->hwndFrom, &ht.pt, 1);

                          TreeView_HitTest(lpnmh->hwndFrom, &ht);
         
                          if(TVHT_ONITEMSTATEICON & ht.flags)
                          {
         
                              
                          }
                     }
                    
            break;
            }
            
      }
      
      return CDialog::OnNotify(wParam, lParam, pResult);
}
Yes I did include include <windowsx.h> and <windows.h> header files
Have u tried with above code given by me with IsItemChecked(HTREEITEM hItem) ?

-MAHESH
Hi Mahesh,
     I have not tried your method yet....it just seemed like it was more involved that the other one.  It's hard to believe that it seems so simple, yet it's not, just to get the state of a checkbox!!!!

Thanks!
>>It's hard to believe that it seems so simple,

code is from above link of same working solution of checkbox with tree...... download and execute to believe
http://www.codeguru.com/cpp/controls/treeview/misc-advanced/article.php/c663/

-MAHESH
Mahesh....I seem to be a bit confused with the solution you have mentioned.  Are we supposed to create 3 separate bitmaps, or one bitmap?
BTW there was no sample code to download and execute in your link.......
ok forget above link........

lets go with yours way : to resolve above error use global API function with scope resolution operator :

::MapWIndowPoints(HWND_DESKTOP, lpnmh->hwndFrom, &ht.pt, 1);


btw To know which Tree Item's check box was clicked in CTreeCtrl.. it will be something like :

// handler of NM_CLICK message
CMyDlg::OnClickTree(......)
{
  DWORD dw = GetMessagePos();
  CPoint pt(GET_X_LPARAM(dw),GET_Y_LPARAM(dw));
  m_Tree.ScreenToClient(&pt);
 
  UINT flags;
  HTREEITEM hItem = m_Tree.HitTest(pt,&flags);
 
  if(hItem)
    TRACE("%s\n",m_Tree.GetItemText(hItem)); // get item text
}

-MAHESH
Mahesh....first, I apperciate your help.  Second, Either I have no idea what i'm doing, or none of the method's that have been mentioned here are working for me.  

I have the NM_CLICK handler for my tree control, and I can do the HitTest etc, to get my item text and so forth(From my first post).  But to check whether the 'checkbox' has been checked, always seems to be one behind.  That's all I am trying to accomplish.

I did create a WM_NOTIFY message as the other person suggested, to no avail.  It never seems to go into my switch statement....

BOOL CDirectoryCheckDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
      //HWND  hWnd  = AfxGetMainWnd()->m_hWnd;

      NMHDR* pNMHDR = (NMHDR*)lParam;


        //CWnd* hWnd = GetActiveWindow();

      switch(pNMHDR->code)
    {
            case WM_NOTIFY:
            {
                     LPNMHDR lpnmh = (LPNMHDR) lParam;
                     TVHITTESTINFO ht = {0};
   
                    
                     if((lpnmh->code  == NM_CLICK) && (lpnmh->idFrom == IDC_TREE1))
                     {
                          DWORD dwpos = GetMessagePos();

                          // include <windowsx.h> and <windows.h> header files
                          ht.pt.x = GET_X_LPARAM(dwpos);
                          ht.pt.y = GET_Y_LPARAM(dwpos);

                              ::MapWindowPoints(HWND_DESKTOP, lpnmh->hwndFrom, &ht.pt, 1);

                          TreeView_HitTest(lpnmh->hwndFrom, &ht);
         
                          if(TVHT_ONITEMSTATEICON & ht.flags)
                          {
                                MessageBox("hello",NULL,NULL);
         
                                        /::PostMessage(this->m_hWnd, UM_CHECKSTATECHANGE, 0, (LPARAM)ht.hItem);


                          }
                     }
                    
            break;
            }
            case UM_CHECKSTATECHANGE:
                  MessageBox("hi",NULL,NULL);
                  break;
            
      }
      
      return CDialog::OnNotify(wParam, lParam, pResult);
}
ASKER CERTIFIED SOLUTION
Avatar of Nass89
Nass89
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial