Thread: Owner Drawn Menus

  1. #1
    Registered User
    Join Date
    Jan 2002

    Owner Drawn Menus

    Does anyone know any tutorials on the internet that cover Owner Drawn Controls, specifically Menus? if you are saying to yourself: "Why would anyone want an owner drawn menu?" well, i am trying to achieve the "Office XP Menu Style", i know how to draw the menu in the client window (using PatBlt()) but i cant find out how to draw ON the menu itself.
    "There are three kinds of people in the world...
    Those that can count and those that can't."

  2. #2
    Registered User
    Join Date
    Aug 2002
    Don't know of any tutorials offhand, sorry. The basic idea however is this:

    --Load or create your menu
    --Set up a MENUITEMINFO structure so fMask = MIIM_TYPE, fType = MFT_OWNERDRAW and dwTypeData = whatever you feel like (usually a pointer to an application defined struc)
    --Set the menu item(s) as owner drawn by calling SetMenuItemInfo.
    --In your parent window proc, handle the WM_MEASUREITEM and WM_DRAWITEM messages. MSDN has good documentation on these items.

    That's basically it.


  3. #3
    pronounced 'fib' FillYourBrain's Avatar
    Join Date
    Aug 2002
    office XP style? do you think that's how they did those? There is a shadow and such that I'm not sure you could simulate with an ownerdraw. I was assuming that they just made their own control rather than using actual menus. I'm probably wrong about that. I'd be curious to hear how it goes.
    "You are stupid! You are stupid! Oh, and don't forget, you are STUPID!" - Dexter

  4. #4
    Registered User
    Join Date
    Aug 2002
    Don't like that solution? Here's another one, although far more involved and invites many bugs.

    --Create 2 custom controls one for the menu bar and one for the popup menus.
    --In each, handle all applicable mouse messages and painting. Make sure to install a timer to handle when your mouse moves in/out of the client area of your custom window otherwise if the mouse moves too fast you'll get items staying high-lighted
    --Don't forget to leave room in the window for extra data -- you're probably gonna need a linked list to store all the menu items, and you'll wanna save the pointer to that list in GWL_USERDATA or similar
    --You'll have to create the menu as a child of your app window. This'll mess up any drawing you were doing in the client area which you can fix either by using creating yet another window or drawing everything about 20 pixels lower.
    Or, you could intercept WM_NCCALCSIZE, reserve yourself some area in the non-client area of the window, create the menu as a child of the desktop and try to coordinate the position and size of the menu bar with the position and size of your parent. Good luck with that one.

    (and I'm pretty sure Office created their own control for this, as you mentioned)

    Have fun


  5. #5
    Registered User
    Join Date
    Jan 2002
    Here is an example of the menu i want to copy (using the API, instead of MFC):

    i tried to look at MSDN before, but i just dont understand what they are doing, thats why i was looking for a tutorial
    "There are three kinds of people in the world...
    Those that can count and those that can't."

  6. #6
    Registered User
    Join Date
    Aug 2002
    Since your original post was about Owner Drawn Menus, here's some code regarding such to get you going. Sorry if it isn't the cleanest... just started C++ a couple of days ago... built it from DevC++ so there's the comments in there...

    There's a cheap resource file, and a skeleton for the WM_DRAWITEM and WM_MEASUREITEM messages.

    The basic idea is this: get the menu. Set the first item as owner-drawn. Then set it to 400 pixels wide. When DrawItem is called, draw a rectangle (green if selected) and then draw some text over top.

    If you wanna add image lists or whatever later it's easy enough to do.


    #include <windows.h>
    char szClassName[ ] = "WindowsApp";
    char szMenuString[ ] = "Some Text";
    HBRUSH selectedbrush;
    int WINAPI
    WinMain (HINSTANCE hThisInstance,
             HINSTANCE hPrevInstance,
             LPSTR lpszArgument,
             int nFunsterStil)
        HWND hwnd;               /* This is the handle for our window */
        MSG messages;            /* Here messages to the application are saved */
        WNDCLASSEX wincl;        /* Data structure for the windowclass */
        /* The Window structure */
        wincl.hInstance = hThisInstance;
        wincl.lpszClassName = szClassName;
        wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */ = CS_DBLCLKS;                 /* Catch double-clicks */
        wincl.cbSize = sizeof (WNDCLASSEX);
        /* Use default icon and mouse-pointer */
        wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
        wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
        wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
        wincl.lpszMenuName = MAKEINTRESOURCE(1001);                 /* No menu */
        wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
        wincl.cbWndExtra = 0;                      /* structure or the window instance */
        /* Use Windows's default color as the background of the window */
        wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
        /* Register the window class, and if it fails quit the program */
        if (!RegisterClassEx (&wincl))
            return 0;
        /* The class is registered, let's create the program*/
        hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szClassName,         /* Classname */
               "Windows App",       /* Title Text */
               WS_OVERLAPPEDWINDOW, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               544,                 /* The programs width */
               375,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /* No menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
        /* Make the window visible on the screen */
        ShowWindow (hwnd, nFunsterStil);
        /* Run the message loop. It will run until GetMessage() returns 0 */
        while (GetMessage (&messages, NULL, 0, 0))
            /* Translate virtual-key messages into character messages */
            /* Send message to WindowProcedure */
        /* The program return-value is 0 - The value that PostQuitMessage() gave */
        return messages.wParam;
    /*  This function is called by the Windows function DispatchMessage()  */
    WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       HMENU hMenu;
       MENUITEMINFO mii;
       HBRUSH bgbrush;
        switch (message)                  /* handle the messages */
            case WM_DESTROY:
                PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            case WM_CREATE:
                selectedbrush = CreateSolidBrush(0xFF00);
                hMenu = GetMenu(hwnd);
                mii.cbSize = sizeof (MENUITEMINFO);
                mii.fMask = MIIM_TYPE;
                mii.fType = MFT_OWNERDRAW;
                mii.dwTypeData = szMenuString;
            case WM_MEASUREITEM:
                lpmis = (LPMEASUREITEMSTRUCT) lParam;
                lpmis->itemWidth = 200;
                lpmis->itemHeight = 20;
            case WM_DRAWITEM:
                lpdis = (LPDRAWITEMSTRUCT) lParam;
                bgbrush = (HBRUSH) GetStockObject(WHITE_BRUSH);
                if (lpdis->itemState == ODS_SELECTED) bgbrush = selectedbrush;
                lpdis->rcItem.left += 2;
                lpdis-> += 2;
            default:                      /* for messages that we don't deal with */
                return DefWindowProc (hwnd, message, wParam, lParam);
        return 0;
    A simple resouce file...
    #define IDM_FILE_EXIT         106
    #define IDM_APPMENU 1001
     POPUP "&File" 
             MENUITEM "E&xit",IDM_FILE_EXIT

  7. #7
    Registered User
    Join Date
    Jan 2002
    Thanks everyone, i figured it all out
    now i am trying to make a custom drawn toolbar to complete my WIndows XP menus :-D <- screenshots of my progress
    "There are three kinds of people in the world...
    Those that can count and those that can't."

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problems defining classes
    By esmeco in forum C++ Programming
    Replies: 47
    Last Post: 10-24-2007, 01:13 PM
  2. Owner Drawn (a few questions)
    By Oldman47 in forum Windows Programming
    Replies: 2
    Last Post: 04-17-2007, 08:21 PM
  3. Multiple Owner Drawn buttons
    By budoka in forum Windows Programming
    Replies: 5
    Last Post: 07-20-2005, 12:19 AM
  4. Multiple Owner Drawn buttons
    By budoka in forum C++ Programming
    Replies: 3
    Last Post: 07-12-2005, 02:00 AM
  5. Owner Drawn dynamic menus
    By cpeschke in forum Windows Programming
    Replies: 0
    Last Post: 04-18-2005, 04:55 PM