Page 1 of 1

Microsoft : Working With Menus - Part III Popup Menus Rate Topic: -----

#1 Martyn.Rae   User is offline

  • The programming dinosaur
  • member icon

Reputation: 556
  • View blog
  • Posts: 1,436
  • Joined: 22-August 09

Posted 21 March 2010 - 03:48 AM

Microsoft : Working With Menus - Part III

Introduction

This tutorial looks at the creation of popup menus.

Creating a Popup Menu

Creating a popup menu is exactly the same as creating a normal menu, except that you start of by using the CreatePopupMenu function to obtain a menu handle. So, to create a popup menu with two items 'Copy' and 'Paste', we would use something like:

    // Create a popup menu ready for use
    popup_menu = CreatePopupMenu();

    MENUITEMINFO menu_item_info;
    memset(&menu_item_info, 0, sizeof(MENUITEMINFO));
    menu_item_info.cbSize = sizeof(MENUITEMINFO);
    menu_item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA;
    menu_item_info.wID = 6;
    menu_item_info.dwTypeData = L"&Cut";
    menu_item_info.cch = 3;
    InsertMenuItem(popup_menu, 0, TRUE, &menu_item_info);
                    
    menu_item_info.wID = 7;
    menu_item_info.dwTypeData = L"&Paste";
    menu_item_info.cch = 5;
    InsertMenuItem(popup_menu, 1, TRUE, &menu_item_info);



Displaying and Tracking A Popup Menu

In order to display and track the popup menu, we need to call TrackPopupMenu. This function tells the menu sub-system where to place the popup menu. In the example, I have included below, I have chosen to display the popup menu using the mouse coordinates at the time the right mouse button is pressed (the lparam parameter of the windows callback function specifies the coordinates). These coordinates are relative to the top left-hand corner of the client window, but TrackPopupMenu requires it's coordinates relative to the top left-hand corner of the screen. We use a function called ClientToScreen to translate the client coordinates into screen coordinates.

Extracting the added code from the example code below you can see that I intercept the right button down message in order to display the popup menu if the user has opened a bitmap. The flags for the TrackPopupMenu say that I want the popup menu to be displayed aligned centre to the x, y coordinates supplied; that the user selects a popup menu item with the left mouse button and I want to receive the id of the menu item selected as the return parameter.

     case WM_RBUTTONDOWN:
     {
         if ( !This->have_bitmap ) return 0;
         POINT point = { LOWORD(lparam), HIWORD(lparam) };
         ClientToScreen(This->window_handle, &point);
         int selection = TrackPopupMenu(This->popup_menu, 
                                        TPM_CENTERALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD,
                                        point.x, point.y, 0,
                                        This->window_handle, NULL);
         switch ( selection ) {
             case 6: MessageBox(window_handle, 
                                L"Cut Menu Item Selected", 
                                L"Popup Menu Selection", 
                                MB_OKCANCEL);
                     break;
             case 7: MessageBox(window_handle, 
                                L"Paste Menu Item Selected", 
                                L"Popup Menu Selection", 
                                MB_OKCANCEL);
                     break;                            
        }
        return 0;
    }



Example Code

The code only has functionality for selecting a .bmp bitmap file; it is only to demonstrate the features covered in this tutorial.

What the code does, is to display a basic frame window with a menu bar that contains one item called 'File'. If you select this menu item, a drop down menu is displayed containing 'Create', 'Open' and 'Close'. Notice that the 'Close' menu item is disabled and grayed (which means that it cannot be selected).

The 'Create' menu does nothing more than display a message box stating that it has been selected.

The 'Open' menu opens a file dialog that permits you to browse your computer for .bmp bitmap files. Find one, and select it, then press the Open button in the bottom right of the dialog (don't worry, the actual file does not get opened). Notice that a new menu item has appeared on the menu bar called 'Edit'. You will also notice that the 'Close' menu item under the 'File' menu has been enabled.

If you now right-click anywhere in the client window area, a popup menu is displayed containing our two menu items 'Cut' and 'Paste'. Select either one of these two menu items, and a message box is displayed confiming the selection.

Now, select the 'Close' menu item, and the 'Edit' menu item is removed from the menu bar. The 'Close' menu item is once again disabled and grayed.

#include <windows.h>
#include <ctime>
#include <cstdlib>
using namespace std;

class frame_window {
    private:    LPWSTR window_class_name;
                HINSTANCE instance_handle;
                HCURSOR cursor_arrow;
                HWND window_handle;
                HMENU menu_handle;
                HMENU edit_sub_menu;
                HMENU image_sub_menu;
                HMENU popup_menu;
                RECT client_rectangle;
                bool have_bitmap;
    public:     frame_window(LPWSTR window_class_identity) : window_class_name(window_class_identity),
                                                             instance_handle(NULL), have_bitmap(false) { 
                    int screen_width = GetSystemMetrics(SM_CXFULLSCREEN);
                    int screen_height = GetSystemMetrics(SM_CYFULLSCREEN);
                    instance_handle = GetModuleHandle(NULL);
                    cursor_arrow = LoadCursor(instance_handle, IDC_ARROW); 
                    WNDCLASS window_class = { CS_OWNDC, main_window_proc, 0, 0,  
                                              instance_handle, NULL,  
                                              cursor_arrow,  
                                              NULL, NULL,  
                                              window_class_name }; 
                 
                    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
                    // Create a standard frame window 
                    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
                 
                    RegisterClass(&window_class); 
                    window_handle = CreateWindowEx(WS_EX_WINDOWEDGE|WS_EX_CLIENTEDGE,  
                                                   window_class_name,  
                                                   L"Bitmap Editor", 
                                                   WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN, 100, 
                                                   100, screen_width-200,  
                                                   screen_height-200, NULL, NULL, 
                                                   instance_handle, NULL);
                    
                    // Create a menu bar and set it into the main window
                    menu_handle = CreateMenu();
                    SetMenu(window_handle, menu_handle);

                    // Create sub menus
                    edit_sub_menu = CreateMenu();
                    image_sub_menu = CreateMenu();
                                                
                    HMENU file_sub_menu = CreateMenu();

                    // Add a file menu item to the menu bar and insert it
                    MENUITEMINFO menu_item_info;
                    memset(&menu_item_info, 0, sizeof(MENUITEMINFO));
                    menu_item_info.cbSize = sizeof(MENUITEMINFO);
                    menu_item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | MIIM_SUBMENU;
                    menu_item_info.fType = MFT_STRING;
                    menu_item_info.wID = 1;
                    menu_item_info.dwTypeData = L"&File";
                    menu_item_info.cch = 4;
                    menu_item_info.hSubMenu = file_sub_menu;
                    InsertMenuItem(menu_handle, 0, TRUE, &menu_item_info);

                    menu_item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA;
                    menu_item_info.wID = 2;
                    menu_item_info.dwTypeData = L"&New";
                    menu_item_info.cch = 3;
                    InsertMenuItem(file_sub_menu, 0, TRUE, &menu_item_info);
                    
                    menu_item_info.wID = 3;
                    menu_item_info.dwTypeData = L"&Open";
                    menu_item_info.cch = 4;
                    InsertMenuItem(file_sub_menu, 1, TRUE, &menu_item_info);
                   
                    menu_item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | MIIM_STATE;
                    menu_item_info.wID = 4;
                    menu_item_info.dwTypeData = L"&Close";
                    menu_item_info.cch = 5;
                    menu_item_info.fState = MFS_DISABLED;
                    InsertMenuItem(file_sub_menu, 2, TRUE, &menu_item_info);

                    // Let the window know that the menu bar has been updated
                    DrawMenuBar(window_handle);

                    menu_item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA;
                    menu_item_info.wID = 6;
                    menu_item_info.dwTypeData = L"&Cut";
                    menu_item_info.cch = 3;
                    InsertMenuItem(edit_sub_menu, 0, TRUE, &menu_item_info);
                    
                    menu_item_info.wID = 7;
                    menu_item_info.dwTypeData = L"&Paste";
                    menu_item_info.cch = 5;
                    InsertMenuItem(edit_sub_menu, 1, TRUE, &menu_item_info);
                    
                    menu_item_info.fMask = MIIM_TYPE;
                    menu_item_info.fType = MFT_SEPARATOR;
                    InsertMenuItem(edit_sub_menu, 2, TRUE, &menu_item_info);

                    menu_item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | MIIM_SUBMENU;
                    menu_item_info.wID = 8;
                    menu_item_info.dwTypeData = L"&Image";
                    menu_item_info.cch = 5;
                    menu_item_info.hSubMenu = image_sub_menu;
                    InsertMenuItem(edit_sub_menu, 3, TRUE, &menu_item_info);
                    
                    menu_item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA;
                    menu_item_info.wID = 9;
                    menu_item_info.dwTypeData = L"C&olour";
                    menu_item_info.cch = 6;
                    InsertMenuItem(edit_sub_menu, 4, TRUE, &menu_item_info);
                    
                    menu_item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA;
                    menu_item_info.wID = 10;
                    menu_item_info.dwTypeData = L"&Dimensions";
                    menu_item_info.cch = 10;
                    InsertMenuItem(image_sub_menu, 0, TRUE, &menu_item_info);
                    
                    menu_item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA;
                    menu_item_info.wID = 11;
                    menu_item_info.dwTypeData = L"&Scale";
                    menu_item_info.cch = 5;
                    InsertMenuItem(image_sub_menu, 1, TRUE, &menu_item_info);
                    
                    // Create a popup menu ready for use
                    popup_menu = CreatePopupMenu();

                    menu_item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA;
                    menu_item_info.wID = 6;
                    menu_item_info.dwTypeData = L"&Cut";
                    menu_item_info.cch = 3;
                    InsertMenuItem(popup_menu, 0, TRUE, &menu_item_info);
                    
                    menu_item_info.wID = 7;
                    menu_item_info.dwTypeData = L"&Paste";
                    menu_item_info.cch = 5;
                    InsertMenuItem(popup_menu, 1, TRUE, &menu_item_info);

                    SetWindowLongPtr(window_handle, GWL_USERDATA, (LONG)this);
                    ShowWindow(window_handle, SW_SHOW); 
                    UpdateWindow(window_handle);
                }
                ~frame_window() {
                    DestroyMenu(image_sub_menu);
                    DestroyMenu(edit_sub_menu);
                    DestroyMenu(popup_menu);
                    UnregisterClass(window_class_name, instance_handle); 
                }
                //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
                // Windows message processing function 
                //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
                static LRESULT WINAPI main_window_proc(HWND window_handle, UINT message,  
                                                       WPARAM wparam, LPARAM lparam) {
                    frame_window *This = (frame_window *)GetWindowLongPtr(window_handle, GWL_USERDATA);
                    switch ( message ) {
                        case WM_PAINT: 
                        { 
                            PAINTSTRUCT paint_structure; 
                            RECT client_rect; 
                            HDC paint_device_context, paint_dc; 
                            HBITMAP bitmap; 

                            paint_device_context = BeginPaint(window_handle, &paint_structure); 
                            paint_dc = CreateCompatibleDC(paint_device_context); 
                            GetClientRect(window_handle, &client_rect); 
                            int window_width = client_rect.right - client_rect.left;
                            int window_height = client_rect.bottom - client_rect.top;
                            bitmap = CreateBitmap(window_width, window_height, 1, 32, NULL);
                            HGDIOBJ old_bitmap = SelectObject(paint_dc, bitmap);

                            // Fill the client aread with the user selected face colour
                            HBRUSH light_brush = CreateSolidBrush(RGB(255, 255, 238));
                            FillRect(paint_dc, &paint_structure.rcPaint, light_brush);
                            DeleteObject(light_brush);
                                                                                  
                            BitBlt(paint_device_context, 0, 0,  
                                   client_rect.right-client_rect.left, 
                                   client_rect.bottom-client_rect.top, 
                                   paint_dc, 0, 0, SRCCOPY); 
                            SelectObject(paint_dc, old_bitmap); 
                            DeleteObject(bitmap); 
                            DeleteDC(paint_dc); 
                            EndPaint(window_handle, &paint_structure); 
                            return 0; 
                        } 
                        case WM_ERASEBKGND: 
                        { 
                            return TRUE; 
                        } 
                        case WM_SIZE: 
                        { 
                            InvalidateRect(window_handle, NULL, TRUE); 
                            return 0; 
                        }
                        case WM_COMMAND:
                        {
                            switch ( LOWORD(wparam) ) {
                                case 2:     MessageBox(window_handle, L"New Menu Item Selected", L"Menu Selection", MB_OKCANCEL);
                                            break;
                                case 3: {   OPENFILENAME open_file_struct;
                                            memset(&open_file_struct, 0, sizeof(open_file_struct));
                                            wchar_t open_file_name[_MAX_PATH] = L"\0";
                                            wchar_t title_text[_MAX_PATH+20];
                                            open_file_struct.lStructSize = sizeof(open_file_struct);
                                            open_file_struct.hwndOwner = NULL;
                                            open_file_struct.hInstance = This->instance_handle;
                                            open_file_struct.lpstrFilter = L"*.bmp\0\0\0";
                                            open_file_struct.lpstrCustomFilter = NULL;
                                            open_file_struct.nFilterIndex = 0;
                                            open_file_struct.lpstrFile = open_file_name;
                                            open_file_struct.nMaxFile = sizeof(open_file_name);
                                            open_file_struct.lpstrFileTitle = NULL;
                                            open_file_struct.lpstrInitialDir = NULL;
                                            open_file_struct.lpstrTitle = NULL;
                                            open_file_struct.Flags = OFN_DONTADDTORECENT | OFN_EXPLORER | OFN_FILEMUSTEXIST | 
                                                                     OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_LONGNAMES |
                                                                     OFN_READONLY;
                                            open_file_struct.FlagsEx = 0;
                                            if ( GetOpenFileName(&open_file_struct) == TRUE ) {
                                                EnableMenuItem(This->menu_handle, 4, MF_BYCOMMAND | MF_ENABLED);
                                                wcscpy(title_text, L"Bitmap Editor : ");
                                                wcscat(title_text, open_file_struct.lpstrFile);
                                                SetWindowText(This->window_handle, title_text);

                                                // Add an edit menu item to the menu bar and insert it
                                                MENUITEMINFO menu_item_info;
                                                memset(&menu_item_info, 0, sizeof(MENUITEMINFO));
                                                menu_item_info.cbSize = sizeof(MENUITEMINFO);
                                                menu_item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | MIIM_SUBMENU;
                                                menu_item_info.fType = MFT_STRING;
                                                menu_item_info.wID = 5;
                                                menu_item_info.fState = MFS_ENABLED;
                                                menu_item_info.dwTypeData = L"&Edit";
                                                menu_item_info.cch = 4;
                                                menu_item_info.hSubMenu = This->edit_sub_menu;
                                                InsertMenuItem(This->menu_handle, 1, TRUE, &menu_item_info);

                                                // Let the window know that the menu bar has been updated
                                                DrawMenuBar(This->window_handle);
                                                This->have_bitmap = true;
                                            }
                                            break;
                                        }
                                case 4: {   EnableMenuItem(This->menu_handle, 
                                                           4,
                                                           MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
                                            SetWindowText(This->window_handle, L"Bitmap Editor");
                                            RemoveMenu(This->menu_handle, 5, MF_BYCOMMAND);
                                            DrawMenuBar(This->window_handle);
                                            This->have_bitmap = false;
                                            break;
                                        }
                            }
                            return 0;
                        }
                        case WM_RBUTTONDOWN:
                        {
                            if ( !This->have_bitmap ) return 0;
                            POINT point = { LOWORD(lparam), HIWORD(lparam) };
                            ClientToScreen(This->window_handle, &point);
                            int selection = TrackPopupMenu(This->popup_menu, 
                                                           TPM_CENTERALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD,
                                                           point.x, point.y, 0,
                                                           This->window_handle, NULL);
                            switch ( selection ) {
                                case 6: MessageBox(window_handle, L"Cut Menu Item Selected", L"Popup Menu Selection", MB_OKCANCEL);
                                        break;
                                case 7: MessageBox(window_handle, L"Paste Menu Item Selected", L"Popup Menu Selection", MB_OKCANCEL);
                                        break;                            
                            }
                            return 0;
                        }
                        case WM_CLOSE: 
                        { 
                            //++++++++++++++++++++++++++++++++++++++++++++++++++++ 
                            // The user wants to close the window 
                            //++++++++++++++++++++++++++++++++++++++++++++++++++++ 
                 
                            PostQuitMessage(0); 
                            return 0; 
                        } 
                    } 
                    return DefWindowProc(window_handle, message, wparam, lparam); 
                } 
                
                //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
                // Windows message loop 
                //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
                void run() {
                    MSG window_message; 
                    while ( GetMessage(&window_message, NULL, 0, 0) ) { 
                        TranslateMessage(&window_message); 
                        DispatchMessage(&window_message); 
                    } 
                }
};
 
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
// Windows main entry point 
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 
int WINAPI wWinMain(HINSTANCE instance_handle, HINSTANCE, LPWSTR, INT) {
    frame_window main_window(L"my base window");
    main_window.run();
    return 0; 
}


This post has been edited by Martyn.Rae: 21 March 2010 - 10:29 PM


Is This A Good Question/Topic? 0
  • +

Page 1 of 1