Ownerdrawn Menu with Colored Linest

Most of the times menu items are strings, but sometimes picture makes more sense than text strings. For example, a color menu should show colors rather than text strings containing names of various colors. It would make more sense for the user if the colors like magenta and cyan are shown as they are going to look like rather than as strings saying "Cyan" and "Magenta". If the colors are shown, their meaning would be crystal clear. Graphics are displayed in the menu using owner-drawn menu items. When a menu containing an owner-drawn menu item is displayed, Windows sends the menu's owner (the window to which the menu is attached) a WM_DRAWITEM message as well as the position where it should be drawn. Windows also supplies a device context in which to do the drawing. The WM_DRAWITEM handler might display a bitmap, or it could use GDI function to literally draw the menu item at the specified location. Before a menu containing an owner-drawn menu item is displayed for the first time, Windows sends the menu's owner a WM_MEASUREITEM message to inquire about the menu item's dimensions. If a submenu contains, say, five owner-drawn menu items, the window that the menu is attached to will receive five WM_MEASUREITEM messages the first time the submenu is displayed and five WM_DRAWITEM messages. Each time the submenu is displayed thereafter, the window will receive five WM_DRAWITEM messages but no further WM_MEASUREITEM messages. The very first step in implementing an owner-drawn menu is to stamp all the owner-drawn menu items with the label MF_OWNERDRAW. Unfortunately, this can't be done using the Resource Editor. Instead, you must either create MF_OWNERDRAW menu items programmatically and add them to your menu with AppendMenu( ) or InsertMenu( ), or use ModifyMenu( ) to add the MF_OWNERDRAW attribute to existing menu items. We have used the second method in our program. The second step is adding an OnMeasureItem( ) handler and associated message-map entry so that your application can respond to WM_MEASUREITEM messages. The OnMeasureItem( ) function receives two parameters. The first parameter is an ID identifying the control to which the message pertains and is meaningless for owner-drawn menus. The second parameter is pointer to a structure of type MEASUREITEMSTRUCT. OnMeasureItem()'s job is to fill in the item Width and item Height fields of this structure, informing Windows of the menu item's horizontal and vertical dimensions, in pixels. To compensate for differing video resolutions, better approach is to base the width and height of items in an owner- drawn menu on some standard such as the SM_CYMENU value returned by ::GetSystemMetrics( ):

p -> itemWidth = ::GetSystemMetrics (SM_CYMENU) * 4 ;
p -> itemHeight = ::GetSystemMetrics (SM_CYMENU) ;

here p is the pointer to MEASUREITEMSTRUCT. SM_CYMENU is the height of the menu bars the system draws for top-level menus. By basing the height of owner-drawn menu items on this value and scaling the width accordingly, you can ensure that owner-drawn menu items will have roughly the same proportions as menu items drawn by Windows. The third and final step in implementing owner-drawn menu items is to provide an OnDrawItem( ) handler and a message-map entry for WM_DRAWITEM messages. Inside OnDrawItem( ) is where the actual drawing is done. This function too receives two parameters. The first item once again is meaningless for owner drawn-menu items. The second parameter is a pointer to a DRAWITEMSTRUCT structure, which contains the following members:

typedef struct tagDRAWITEMSTRUCT
UINT CtlType ;
UINT itemID ;
UINT itemAction ;
UINT itemState ;
HWND hwndItem ;
RECT rcItem ;
DWORD itemData ;

The field CtlType of DRAWITEMSTRUCT is set to ODT_MENU if the message pertains to an owner-drawn menu item. The field itemID holds the menu item ID, whereas the fields CtlID and itemData are unused. hDC holds the handle of device context in which the menu item is drawn, and rcItem is a RECT structure containing the coordinates of the rectangle in which the item appears. The size of the rectangle described by rcItem is based on the dimensions you provided to Windows in response to the WM_MEASUREITEM message for this particular menu item. hwndItem holds the handle of the menu to which the menu item belongs. This value isn't often used because the other fields provide most or all of the information that's needed. DRAWITEMSTRUCT's itemState field describes the current state of the menu item - checked or unchecked, enabled or disabled, and so on. These states are indicated using zero or more bit flags as shown in the table below.

ODS_CHECKED: The menu item is currently checked.
ODS_DISABLED: The menu item is currently disabled.
ODS_GRAYED: The menu item is currently grayed.
ODS_SELECTED: The menu item is currently selected.

This state information is important because it tells you how the menu item should be drawn. Which of the bit flags you examine depends on which states you allow the menu item to assume. You should always check the ODS_SELECTED flag and highlight the menu item if the flag is set. If your application includes code to check and uncheck owner-drawn menu items, you should check ODS_CHECKED and draw a check mark next to the menu item if the flag is set. Similarly, if you allow the item to be enabled and disabled and grayed and ungrayed, you should check for ODS_DISABLED and ODS_GRAYED flag and draw accordingly.

No comments: