• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 4608
  • Last Modified:

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;
}
0
arunykand
Asked:
arunykand
  • 6
  • 5
  • 2
1 Solution
 
mahesh1402Commented:
0
 
mahesh1402Commented:
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
0
 
Nass89Commented:
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!
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
arunykandAuthor Commented:
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);
}
0
 
arunykandAuthor Commented:
Yes I did include include <windowsx.h> and <windows.h> header files
0
 
mahesh1402Commented:
Have u tried with above code given by me with IsItemChecked(HTREEITEM hItem) ?

-MAHESH
0
 
arunykandAuthor Commented:
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!
0
 
mahesh1402Commented:
>>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
0
 
arunykandAuthor Commented:
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?
0
 
arunykandAuthor Commented:
BTW there was no sample code to download and execute in your link.......
0
 
mahesh1402Commented:
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
0
 
arunykandAuthor Commented:
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);
}
0
 
Nass89Commented:
Hi,

I checked the codes in MSDN and changed it to the followings:

Add a user defined message to your dialog as here:

//Ofcourse define UM_CHECKSTATECHANGE befor these codes and the function in header file

BEGIN_MESSAGE_MAP(CDirectoryCheckDlg, CDialog)
.....
      ON_MESSAGE(UM_CHECKSTATECHANGE, OnUserMessage)
......
END_MESSAGE_MAP()


Add the following members to your dialog

BOOL CDirectoryCheckDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
      // TODO: Add your specialized code here and/or call the base class
 
      LPNMHDR lpnmh = (LPNMHDR) lParam;
   TVHITTESTINFO ht = {0};
   
   if((lpnmh->code  == NM_CLICK) && (lpnmh->idFrom == IDC_TREE1))
   {
      DWORD dwpos = GetMessagePos();
//      MessageBox("Check", "Click", MB_OK);

      // 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)
      {
         
         PostMessage(UM_CHECKSTATECHANGE, 500, (LPARAM)ht.hItem);
      }
   }
      
      return CDialog::OnNotify(wParam, lParam, pResult);
}
void
CDirectoryCheckDlg::OnUserMessage(WPARAM wParam, LPARAM lParam)
{
      

  HTREEITEM   hItemChanged = (HTREEITEM)lParam;

  if(m_testTree.GetCheck(hItemChanged))
      MessageBox("It is really checked", "Hiiiiiiiiiii", MB_OK);
  else
      MessageBox("IT IS NOT CHECKECD", "Hiiiiiiiiiii", MB_OK);


}

I tested the above codes and it works!!!!

Try it and good luck!


0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

  • 6
  • 5
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now