Floating Pop-Up Menus

--Keegan Roth

Thoughts

Free-floating menus require minimal effort on part of the user, opposed to the equivalent of going through the normal menuing system. Through the Visual C++ environment, implementation of floating pop-up menus is a simple and straightforward process.

Overview

In this procedure you will create a single button in a single-document interface and program a pop-up menu to move and re-size the button. This example will show you the basic ideas behind the implementation of floating pop-up menus.

Procedure

  1. Start Visual C++
  2. From the menu select File..New
  3. A dialog box name New will appear. In it select MFC AppWizard (exe), enter a project name of Pop and click OK
  4. In the first step of the AppWizard select Single Document Interface and click Finish
  5. Click OK in the New Project Information dialog box
  6. First you will create the button that will be on the screen

  7. Open PopView.h
  8. After CPopDoc* GetDocument(); add the line:
  9. int x,y,width,height;

    CButton Button;

  10. Close PopView.h
  11. Press Ctrl-W to bring up the ClassWizard
  12. With both Class Name and Object ID having CPopView selected, double-click on Create in the Messages listbox, then click Edit Code
  13. Change the body of Create() to look like this:
  14. int temp = CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);

    temp = temp && Button.Create("Test",BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE,CRect(x,y,x+width,y+height),this,100);

    return temp;

  15. Scroll up until you find CPopView::CPopView()
  16. In the body of CPopView() add the following initializations:
  17. x = y = 30;

    width = height = 50;

  18. Close the PopView.cpp window
  19. You will now create the menu that will be the floating pop-up

  20. In the Workspace side-window (if this is not visible; right click in the dark gray area inside the Developer Studio document area and check Workspace) open the ResourceView tab
  21. Expand Pop Resources, then right-click on Menu and select Insert Menu
  22. Right-click on IDR_SPACIAL and select Properties
  23. Select the first entry of the blank menu bar and type Spacial, then hit enter
  24. The next position under Spacial will be selected, at that point type Move
  25. Still inside the Menu Items Properties window check Pop-up, then hit enter
  26. Select the blank extension of to the right of Move, type X
  27. Make sure the menu item's ID field is set to ID_SPACIAL_MOVE_X
  28. Select the blank below the X, type Y
  29. Verify that this menu item's ID field is set to ID_SPACIAL_MOVE_Y
  30. Select the blank entry below Move and type Size, then check Pop-up and close the window
  31. Select the blank extension to the right of Size, type Width
  32. Set the ID field for this menu item to ID_SPACIAL_SIZE_WIDTH
  33. Select the blank below Width, type Height
  34. The ID for this menu item should be ID_SPACIAL_SIZE_HEIGHT
  35. Close the menu window
  36. You will now link these menu messages to the code you want to implement.

  37. Press Ctrl-W to open the ClassWizard
  38. If you are prompted to decide whether you want a new class for the menu, choose Select an existing class, then pick PopView as the class
  39. Set the Class Name to CPopView and the Object ID to ID_SPACIAL_MOVE_X, in Messages double-click on Command, and confirm the function name
  40. Follow step 28 for each of the following IDs: ID_SPACIAL_MOVE_Y, ID_SPACIAL_SIZE_WIDTH, and ID_SPACIAL_SIZE_HEIGHT
  41. In Member Functions select OnSpacialMoveX then Click Edit Code
  42. Button was declared as an object of the class CButton, which descends from the CWnd class. For every CWnd object and any object descendent of CWnd is defined a member function MoveWindow that allows the object to be moved and resized. The first and second parameters specifies the new X and Y positions. The third and fourth specifies the new width and height. If you want the button to be invalidated at that time so that it will be re-drawn, you would set the fifth and final parameter to true, otherwise set it to false.

  43. Add code to make the body of OnSpacialMoveX() look like this:
  44. x += 5;

    Button.MoveWindow(x,y,width,height,true);

  45. Scroll down and edit the body of OnSpacialMoveY() with these lines:
  46. y += 5;

    Button.MoveWindow(x,y,width,height,true);

  47. Find OnSpacialSizeWidth() and insert these lines in the body:
  48. width += 5;

    Button.MoveWindow(x,y,width,height,true);

  49. Locate OnSpacialSizeHeight() and add a body that looks like this:
  50. height += 5;

    Button.MoveWindow(x,y,width,height,true);

    Menus can be retrieved and stored into CMenu objects with a member function LoadMenu(UINT nIDResource). Within each menu there can be multiple entries. A CMenu pointer to these submenus can be retrieved by calling the CMenu member function GetSubMenu(int nPos) after LoadMenu() has been called. NPos refers to the zero-based index position of which menu item to retrieve. Since you only created one entry (Spacial) then you want to retrieve the first index, or zero. To initiate the floating menu the CMenu member function TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL ) is called.

    In order to make the floating menu appear only when the user clicks on the button you must first get the button's dimensions with a GetWindowRect() call. The CRect class defines a function called PtInRect(CPoint point) that returns true if point lies within the CRect, false if it does not. With this condition, you can call TrackPopupMenu to do the floating menu only when there is a click on the button.

  51. Press Ctrl-W to get the ClassWizard
  52. Set both Class Name and Object ID to CPopView
  53. In Messages double-click WM_CONTEXTMENU, then click Edit Code
  54. Add the following code to the body of OnContextMenu
  55. CMenu Menu;

    CMenu *subMenu;

    Menu.LoadMenu(IDR_SPACIAL);

    CRect rect;

    Button.GetWindowRect(rect);

    if(rect.PtInRect(point)) {

    subMenu = Menu.GetSubMenu(0);

    subMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x,point.y,this);

    }

  56. Now compile and execute your application with Ctrl-F5 then click OK when asked to recompile dependencies. Right click on the button and try each of the menu items. Notice that if you do not right click directly on top of the button, then the menu will not appear.

You now should have a basic understanding of how a floating pop-up menu is implemented. From this knowledge you can increase the level of functionality in your applications a great deal.