Tree Control

I have written the following code as an handler when an item in a Tree Control is right clicked.

NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
    CTreeCtrl* pTree = (CTreeCtrl*) GetDlgItem(IDC_TREEVIEW);
    HTREEITEM hSelected = pNMTreeView->itemNew.hItem;

But i am getting hSelected as NULL always

What could be the error ???

Thanks in advance!!!
VS_LearnerAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

KurtVonCommented:
According to MS docs:

itemNew
TV_ITEM structure that contains information about the new item state. This member is zero for messages that do not use it.

Unfortunately, since right clicking does not actually select an item in the tree, the value here is 0.  On the bright side, that means you aren't doing anything wrong, Windows is just being annoying.  If you want to find out where the right-click occurred, you need to use the ptDrag to find the item under the cursor.  Unfortunately this means stepping through a loop with GetNextVisibleItem and GetItemRect sinc ethere is no GetItemFromPoint member of CTreeCtrl.

Hope this helps.
0
VS_LearnerAuthor Commented:
Could anyone present a sample code as to how to find the item(in the tree control) on which the right click has occured??

Thanks
0
KurtVonCommented:
Hmm, I have some such code at home, but that would take a while to get (that's why I recognized your problem, went through the same thing myself).  It went something like:

CRect rcItem;
HTREEITEM hItem = m_TreeCtrl.GetFirstVisibleItem();
while (hItem != NULL)
{
    m_TreeCtrl.GetItemRect(hItem, rcItem, FALSE);
    if (rcItem.PtInRect(pNMTreeView->ptDrag)
        break;
    else
        hItem = m_TreeCtrl.GetNextVisibleItem(hItem);
}

if (hItem != NULL)
{
    // The non-null hItem is the item that was clicked in.
}

This was done by hand, so watch out for typos.

Hope this helps.
0
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

VS_LearnerAuthor Commented:
Hi KurtVon ,
                Thanks for writing the code . But unfortunately i am getting the hItem as NULL always irrespective of where ever i click.
Like it is never going into the 'if loop' .so its never breaking and hItem is always becoming NULL.
And i think in the code while calling the function GetItemRect ..the second argument should be a pointer to the CRect structure.(coz..its an input parameter i guess.).But still the code isn't working.
I have also tried calling GetCursorPos and giving that point as an argument to PtInRect ..But even that isn't working.

So please help me out in finding out the error!!!!!!!

Thanks again.!!!
0
KurtVonCommented:
Hmm, the code works perfectly for me.  What message are you trapping?  I used the TVN_BEGINRDRAG, but that meant I had to move the mouse a bit while the button was down.

And the CRect should not be a pointer.  GetItemRect takes a pointer to a RECT, but a CRect can be a pointer to a RECT through a typecast.  Using the & will work too, but only because a CRect is descended from RECT and has no virtual functions.  In general, typecast operators are safer than assumptions like that.
0
VS_LearnerAuthor Commented:
I am trapping the NM_RCLICK ( right mouse click )..Like I want to display a menu (when right-clicked ) to only some items in the tree control.So i want to know whether an item is clicked or not , and if clicked which item?? Hope I am clear .!

Thanks
0
KurtVonCommented:
NM_RCLICK only notifies when the mouse button is released.  But if that's okay, the problem is simple, the notification message does not send a NM_TREEVIEW object.  To get the mouse position you will need to use this code:

    CPoint ptDrag;
    GetCursorPos(&ptDrag);
    m_TreeCtrl.ScreenToClient(&ptDrag);

then just check the CRect position with ptDrag.

Hope this helps.
0
VS_LearnerAuthor Commented:
I have already tried this code (i.e using GetCursorPos to get the point ) , but unfortunately i am getting hItem as NULL always ..
0
KurtVonCommented:
I assume you did the ScreenToClient too (for the control).  Very odd since it works perfectly for me.

Does it do into the while loop, or does it skip over the loop on the first try?  If it skips, then GetFirstVisibleItem is returning NULL, which would mean that the tree control is reporting no visible items.  If it is going into teh loop, but not finding any item for the rectangle, it may be that GetItemRect has the third parameter set to TRUE somehow, and is only allowing teh selection of text.  Try clicking on the text itself.

Hope this helps.
0
VS_LearnerAuthor Commented:
Irrespective of whereever i click , it is going through the while loop i ( i = GetVisibleCount) number of times. And that "i" value is perfectly right..(I checked it ) . It is only that in the "while" loop always "else" is getting executed. I have also checked everyother possible thing.The only thing is that , the point where i click is "never" in the rectangle of any visible item.

Thanks
0
KurtVonCommented:
What are the coordinates of the click point?  It almost sounds like ScreenToClient isn't working properly.  Make sure you are calling it for the tree control object, not for the dialog.  Also check the coordinates of the rectangles.

Also make sure you really are using the point collected in GetCursorPos to compare against the rectangles.  If that still doesn't work, could you post the code up to the end of the while loop?  I'll compare it to what I have and see if I can find the problem.
0
VS_LearnerAuthor Commented:

Here is the code upto end of while loop...

void CFolderPage::OnNMRclickTreeview(NMHDR *pNMHDR, LRESULT *pResult)
{

        CRect rcItem;

       HTREEITEM hItem = m_treectrl.GetFirstVisibleItem();
       while (hItem != NULL)
      {
      m_treectrl.GetItemRect(hItem, rcItem, FALSE);
      POINT point ;
      GetCursorPos(&point) ;
      m_treectrl.ScreenToClient(&point);
      if ( rcItem.PtInRect(point) )
            break;
      else
            hItem = m_treectrl.GetNextVisibleItem(hItem);
      }
0
KurtVonCommented:
Odd, that looks like it should work.  You can make the code more efficient by taking the GetCursorPos out of the while loop (since you only care about where the curosr was when the loop was entered).  of course, it will not work while debugging since the mouse is moved, so test it without a breakpoint or make sure the breakpoint is after the cursor position is retrieved:

void CFolderPage::OnNMRclickTreeview(NMHDR *pNMHDR, LRESULT *pResult)
{
    CRect rcItem;
    POINT point ;

    GetCursorPos(&point) ;
    m_treectrl.ScreenToClient(&point);
    HTREEITEM hItem = m_treectrl.GetFirstVisibleItem(); // put breakpoint here or later
    while (hItem != NULL)
    {
        m_treectrl.GetItemRect(hItem, rcItem, FALSE);
        if ( rcItem.PtInRect(point) )
            break;
        else
            hItem = m_treectrl.GetNextVisibleItem(hItem);
    }

that way the cursor position will be where you clicked rather than where you moved the mouse after it was hit.  Then check the point against each rect and see if it makes any more sense why it wouldn't work.

Hope this helps.
0
VS_LearnerAuthor Commented:
Hey ...Its working!!!...when i moved the 3 lines ( getting cursor pos) above the while loop.Its working fine..!!!
Thank You Very much for taking some time to test the code.
Actually now i got the actual error..!!! when i added debugging code ( like putting some messageboxes ) the cursor is moving to the "ok" button of the messagebox and the actual click point is missing everytime when it enters the while loop!!!

Thanks Once Again!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
0
VS_LearnerAuthor Commented:
I need to attach the same functionality for a list control box...So can i use the same type of code for that too..Or any changes are required???

Thank You
0
KurtVonCommented:
To do this with a list control is easier, since CListCtrl::HitTest will return the index of the item the point is in automatically, so no need for the while loop.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.

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.