Right button popup menu

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

Submitted by Christopher A. Snyder.

The CTreeView class does not handle the right mouse button click in a manner like the Explorer window. Actions like highlighting, setting the active item, and where the right mouse menu pops up require some additional code to obtain the appropriate functionality. This article is intented to illustrate what functions need to be added to your view class for the tree to "act" properly.

(this page was revised to correct several typos and to address the SHIFT-F10 keypress. Revision date 2-20-98)

How this works

What need to happen when a user presses the right mouse button is the selected item needs to change, but not the item in focus. In addition the pop-up context sensitive menu should be display at the corner where the mouse clicked. By default, this does not happen. These code additions shift the focus of a tree item based on the where the mouse click occurs. However, when the right mouse button click is completed, (or after the context menu goes away) the selection needs to shift back to the original selected tree item. This is done in the end of the OnContextMenu function through the use of an added member variable.

To handle the SHIFT-F10 key press, this is the keyboard equivalent of a right mouse button click for those who didn't know that (I never use it so I tend to forget it is there), we need to handle the key press command mirrored from the Tree control. The code I have here for this is more a quick fix than a good solution (if someone has a better method send it to me and I will have it updated here). I first look for a shift key press and then set a flag. Then only when the next key pressed is the F10 do I then call the on-context menu function. This is not a real good solution because the use does not have to hold the shift key down to get the menu to pop up. Though it is close and not too big of a deal since few probably even use the SHIFT-F10 sequence anyways.

To add a Right mouse button context sensitive popup menu to a CTreeView which behaves like the Explorer. To do this you need to add command handler functions for the following messages in your CTreeView derived class (CMyTreeView).

There is one more function that I created here to actually create and display you menu from a menu resource and is called

ShowPopupMenu( CPoint& point );

You will need to add one member variable to CMyTreeView called m_pOldSel. Enjoy!

class CMyTreeView : public CTreeView
        // Generated message map functions
        afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
        afx_msg void OnKeydown(NMHDR* pNMHDR, LRESULT* pResult);

        afx_msg void OnContextMenu(CWnd*, CPoint point);
        void CMyTreeView::ShowPopupMenu( CPoint& point );
// member variables
        HTREEITEM m_pOldSel;
Place this code in the created functions.
void CMyTreeView::OnLButtonDown(UINT nFlags, CPoint point)
        UINT uFlags;
        HTREEITEM htItem = GetTreeCtrl().HitTest(point, &uFlags);
        if ((htItem != NULL) && (uFlags & TVHT_ONITEM))
                GetTreeCtrl().Select(htItem, TVGN_DROPHILITE);
        CTreeView::OnLButtonDown(nFlags, point);

void CMyTreeView::OnRButtonDown(UINT nFlags, CPoint point)
        UINT uFlags;
        HTREEITEM htItem = GetTreeCtrl().HitTest(point, &uFlags);
        if ((htItem != NULL) && (uFlags & TVHT_ONITEM)) {
                m_pOldSel = GetTreeCtrl().GetSelectedItem();
                GetTreeCtrl().Select(htItem, TVGN_DROPHILITE);

void CMyTreeView::OnContextMenu(CWnd* pWnd, CPoint point)
        UINT uFlags;
        CTreeCtrl&      treeCtrl = GetTreeCtrl();
        CPoint ptTree = point;
        HTREEITEM htItem = treeCtrl.HitTest(ptTree, &uFlags);

        if ((htItem != NULL) && (uFlags & TVHT_ONITEM)) {
                ShowPopupMenu( point );
                treeCtrl.SetItemState(htItem, 0, TVIS_DROPHILITED);
                CTreeView::OnContextMenu(pWnd, point);

        if (m_pOldSel != NULL) {
                treeCtrl.Select(m_pOldSel, TVGN_DROPHILITE);
                m_pOldSel = NULL;

void CMyTreeView::ShowPopupMenu( CPoint& point )
        if (point.x == -1 && point.y == -1){
                //keystroke invocation
                CRect rect;

                point = rect.TopLeft();
                point.Offset(5, 5);

        CMenu menu;

        CMenu* pPopup = menu.GetSubMenu(0);
        ASSERT(pPopup != NULL);
        CWnd* pWndPopupOwner = this;

        while (pWndPopupOwner->GetStyle() & WS_CHILD)
                pWndPopupOwner = pWndPopupOwner->GetParent();

        pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,

/*       121 vbKeyF10  16 = shift */
// there is probably a more elegant way to handle this, but this method works.
void CMyTreeView::OnKeydown(NMHDR* pNMHDR, LRESULT* pResult) 
        static BOOL bShift = FALSE;
        if ( bShift && pTVKeyDown->wVKey == 121 ) {
                HTREEITEM hItem = GetTreeCtrl().GetSelectedItem( );
                CRect rect;
                GetTreeCtrl().GetItemRect( hItem, &rect, TRUE);
                ClientToScreen( rect );
                OnContextMenu( this, CPoint( rect.right, rect.top ) );
        bShift = pTVKeyDown->wVKey == 16;

        *pResult = 0;
Chris is a reseach engineer for the Ohio University Avionics Engineering Center.
Feel Free to e-mail him with questions or comments.

Revised on : 3/15/98



    Posted by RaymondCai on 03/10/2007 01:26pm

    I very appreciate that you shared your idea and code. it helps me a lot. But there is a very funny thing that I can not make right click working for popup menu, I need to double click right botton to popup menu. It seems the only one click did not send message WM_CONTEXTMENU to my program. I know there is some problem of my code, but where? Thanks.

  • Something Wrong

    Posted by Legacy on 01/23/2003 12:00am

    Originally posted by: Cagatay Tunali

    This code works only;
    user must left click the menu item before right clicking the menu item. this combination will make the code work.
    but if you select an item in the list, and after that if you right click another item this code does not work correctly. the selected item and the right clicked item is different.

    i discover this when i try to disable the menu item when root is clicked and eanble when a chld is clicked. is there a method to solve this problem. thank you fro your comments and codes.......

  • Shift-F10 even easier...

    Posted by Legacy on 01/06/2003 12:00am

    Originally posted by: Greg Williams

    I found that I didn't need to explicitly handle the keypress for Shift-F10 (or the context menu key), the WM_CONTEXTMENU message was automatically generated with (-1, -1) as the point passed.

    Btw, CTreeCtrl::SelectDropTarget(item) is equivalent to CTreeCtrl::Select(item, TVG_DROPHILITE).

  • You don't need ShowPopupMenu(...)

    Posted by Legacy on 09/27/2002 12:00am

    Originally posted by: Simon

    .. just put in OnContextMenu(...) code like this:

    if ((htItem != NULL) && (uFlags & TVHT_ONITEM))
    CMenu menu;
    CMenu* pPopup = menu.GetSubMenu(0);
    ASSERT(pPopup != NULL);
    pPopup->TrackPopupMenu(TPM_RIGHTBUTTON | TPM_CENTERALIGN, point.x, point.y, this, NULL);
    //ShowPopupMenu( point );
    pCtrl->SetItemState(htItem, 0, TVIS_DROPHILITED);
    else ....

    For me this also solved the problems that I had with graying and enabling the menu items.

  • The fight against MFC

    Posted by Legacy on 09/09/2002 12:00am

    Originally posted by: Anders Borch

    These days it's almost impossible to get ANY work done without MFC. Microsoft sure did make life difficult for the non-mfc programmer. But I was taught windows programming by Charles Petzold's fine book, so I do my best to stay out of mfc's way. I fought a long battle to get something like this to work without mfc, and finally gave up. I throught that the one sure way to ALWAYS get the right coordinates of the mouse event (even though the tree view does it's best not to give it to me) was through a mouse hook.

    The NM_RCLICK notifies me that right mouse button was clicked, and I react appropriately. All I need is the right screen coordinates for my popup menu.

    I ended up hooking mouse messages to my thread:

    // global
    HHOOK g_hook ;
    POINT g_point ;


    // then in my initialization code
    g_hook = SetWindowsHookEx (WH_MOUSE, MouseProc, hInstance, GetCurrentThreadId()) ;


    // and in my cleanup code
    UnhookWindowsHookEx (g_hook) ;


    // MouseProc was implemented like this:
    RESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) {
    if (code == HC_ACTION) {
    g_point.x = mhs->pt.x ;
    g_point.y = mhs->pt.y ;
    return CallNextHookEx (g_hook, code, wParam, lParam) ;

  • How to implement CTreeCtrl right click Pop up Menu on Dialog?

    Posted by Legacy on 07/18/2002 12:00am

    Originally posted by: eko sulistyo a

    Within CTreeView derived class your method is applicable, but when i'm using CTreeCtrl on My dialog the method is unapplicable. Could you help me with this ?

  • TreeCtrl - Right button popup menu:How to enable/disable menu item?

    Posted by Legacy on 05/14/2002 12:00am

    Originally posted by: Mon


    In this sample how will I enable or disable any menu item(Right button popup menu).I tried the function EnableMenuItem() function but its not working.Do i need to do some thing extra??


  • And another way to do it

    Posted by Legacy on 11/18/2001 12:00am

    Originally posted by: Cla Tischhauser

    How about this solution:

    - Create a popup "Dummy"

    - access it as follows:

    Private Sub TreeView_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Long, ByVal y As Long)
    'check if right-click AND click on a node
    If Button = 2 And Not TreeView.HitTest(x, y) Is Nothing Then
    'select the node in TreeView
    Set TreeView.SelectedItem = TreeView.HitTest(x, y)
    'show popup
    End If
    End Sub

  • Another easy wait to do this

    Posted by Legacy on 10/01/2001 12:00am

    Originally posted by: SCAGNI S�bastien

     To do this, i use the NM_RCLICK event. This event is use when the user has clicked the right mouse button within the control. So with the GetMessagePos() we can get the cursor position into the screen.

    See the code below :

    BEGIN_MESSAGE_MAP(CStationInfoPage, CPropertyPage)

    void CStationScriptPage::OnRclickTree(NMHDR* pNMHDR, LRESULT* pResult)
    CRect TreeRect;
    HTREEITEM hItem = m_treectrl.GetFirstVisibleItem( );

    // Get the the cursor position into the screen
    DWORD Result = GetMessagePos();
    CPoint ItemPos(GET_X_LPARAM(Result), GET_Y_LPARAM(Result));

    // Retreive the coordinates of the treecrtl viwndow
    ItemPos.Offset(-TreeRect.left, -TreeRect.top);

    // Surche the item which have the focus right click. Is not the same think to the selected
    // item. During the right click, the item receive a selected option, but the selected item
    // not change.
    CRect ItemRect;
    m_treectrl.GetItemRect( hItem, &ItemRect, FALSE );

    // If thye scursor is in the bounding rectangle
    ItemPos.Offset(TreeRect.left, TreeRect.top);

    // If the Item is a main parent (no have parent) or have a children, use the SCRIPT_MAIN_
    if(m_treectrl.ItemHasChildren( hItem ) || !m_treectrl.GetParentItem( hItem ))
    CMenu tmpMenu;

    CMenu* pPopup = tmpMenu.GetSubMenu(0);
    ASSERT(pPopup != NULL);

    if(tmpMenu.GetSafeHmenu( ))
    ItemPos.x, ItemPos.y,
    AfxGetMainWnd()); // use main window for cmds
    CMenu tmpMenu;

    CMenu* pPopup = tmpMenu.GetSubMenu(0);
    ASSERT(pPopup != NULL);

    if(tmpMenu.GetSafeHmenu( ))
    ItemPos.x, ItemPos.y,
    AfxGetMainWnd()); // use main window for cmds

    // Get the next visible item.
    hItem = m_treectrl.GetNextVisibleItem( hItem );

    *pResult = 0;

  • It works, but why does it require a double click?

    Posted by Legacy on 09/16/2001 12:00am

    Originally posted by: Michael Pliam

    Using your code in a VCPP6.0 dialog-based app, I can get the popup menu to work just fine, but it takes two clicks (or a double click??) to get it to come up. One click simply doesnt do it. This is annoying and puzzling both. Any ideas how I can eliminate the need for double clicking?


  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • With the cloud transforming application development and deployment — enabling organizations to improve flexibility, automate processes, and decrease time to market — some big questions remain. One of the most important issues an organization must address is how it can best employ the smarter tools and limitless scale that the cloud offers. One way that enterprises take advantage of the benefits of the cloud is by deploying their own private cloud. Read this white paper to learn how private clouds …

  • On-demand webcast Lately it seems that everywhere you turn, there's another cybersecurity breach — and hackers and thieves are never satisfied with the status quo, continuing to refine their tactics or create new methods of attack. So how do you protect your business now, but also plan for your future security needs? How can you guard against this ever-changing threat landscape? Watch Jeremy Smolik, Systems Engineer at Kaspersky Lab North America, in this on-demand webinar as we explore the biggest …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date