PMGuide - Menus: Difference between revisions
Line 219: | Line 219: | ||
After you make this call, the operating system automatically includes the menu in the window, drawing the menu bar across the top of the window. When the user chooses an item from the menu, the menu posts the message to the frame window. The frame window passes any WM_COMMAND messages to the client window. (The frame window does not pass WM_SYSCOMMAND messages to the client window.) WM_HELP messages are posted to the focus window. The WinDefWindowProc function passes WM_HELP messages to the parent window. If a WM_HELP message is passed to a frame window, the frame window calls the HK_HELP hook. Your client window procedure must process these messages to respond to the user's actions. | After you make this call, the operating system automatically includes the menu in the window, drawing the menu bar across the top of the window. When the user chooses an item from the menu, the menu posts the message to the frame window. The frame window passes any WM_COMMAND messages to the client window. (The frame window does not pass WM_SYSCOMMAND messages to the client window.) WM_HELP messages are posted to the focus window. The WinDefWindowProc function passes WM_HELP messages to the parent window. If a WM_HELP message is passed to a frame window, the frame window calls the HK_HELP hook. Your client window procedure must process these messages to respond to the user's actions. | ||
===Creating a Pop-up Menu=== | ===Creating a Pop-up Menu=== | ||
The following code fragment shows how to make a pop-up menu appear when the user double-clicks mouse button 2 anywhere in the parent window. The menu is positioned with the mouse pointer located on the item having the IDM_OPEN identifier and is constrained horizontally and vertically. Then, the user can select an item from the pop-up menu using mouse button 2. | |||
<PRE> | |||
#define ID_MENU_RESOURCE 110 | |||
#define IDM_OPEN 120 | |||
HWND hwndFrame; | |||
MRESULT ClientWndProc( | |||
HWND hwnd, | |||
ULONG msg, | |||
MPARAM mp1, | |||
MPARAM mp2) | |||
{ | |||
HWND hwndMenu; | |||
BOOL fSuccess; | |||
switch (msg) { | |||
. | |||
. /* Process other messages. */ | |||
. | |||
case WM_BUTTON2DBLCLK: | |||
hwndMenu = WinLoadMenu(hwnd, (HMODULE) NULL, ID_MENU_RESOURCE); | |||
fSuccess = WinPopupMenu(hwnd, | |||
hwndFrame, | |||
hwndMenu, | |||
20, | |||
50, | |||
IDM_OPEN, | |||
PU_POSITIONONITEM | | |||
PU_HCONSTRAIN | | |||
PU_VCONSTRAIN | | |||
PU_MOUSEBUTTON2DOWN | | |||
PU_MOUSEBUTTON2); | |||
. | |||
. | |||
. | |||
</PRE> | |||
===Adding a Menu to a Dialog Window=== | ===Adding a Menu to a Dialog Window=== | ||
===Accessing the System Menu=== | ===Accessing the System Menu=== |
Revision as of 05:43, 28 April 2025
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
About Menus
A menu always is owned by another window, usually a frame window. When a user makes a choice from a menu, the menu posts a message containing the unique identifier for the menu item to its owner by way of the owner window's window procedure.
An application typically defines its menus using Resource Compiler, and then associates the menus with a frame window when the frame window is created. Applications also can create menus by filling in menu-template data structures and creating windows with the WC_MENU class. Either way, applications can add, delete, or change menu items dynamically by issuing messages to menu windows.
Menu Bar and Pull-Down Menus
A typical application uses a menu bar and several pull-down submenus. The pull-down submenus ordinarily are hidden, but become visible when the user makes selections in the menu bar. Pull-down submenus always are attached to the menu bar.
The menu bar is a child of the frame window; the menu bar window handle is the key to communicating with the menu bar and its submenus. You can retrieve this handle by calling WinWindowFromID, with the handle of the parent window and the FID_MENU frame-control identifier. Most messages for the menu bar and its submenus can be issued to the menu-bar window. Flags in the messages tell the window whether to search submenus for requested menu items.
Pop-Up Menus
A pop-up menu is like a pull-down submenu, except that it is not attached to the menu bar; it can appear anywhere in its parent window. A pop-up menu usually is associated with a portion of a window, such as the client window, or it is associated with a specific object, such as an icon.
A pop-up menu remains hidden until the user selects it (either by moving the cursor to the appropriate location and pressing Enter or clicking on the location with the mouse). Typically, pop-up menus are displayed at the position of the cursor or mouse pointer; they provide a quick mechanism for selecting often-used menu items.
To include a pop-up menu in an application, you first must define a menu resource in a resource-definition file, then load the resource using the WinLoadMenu or WinCreateMenu functions. You must call WinPopupMenu to create the pop-up menu and display it in the parent window. Applications typically call WinPopupMenu in a window procedure in response to a user-generated message, such as WM_BUTTON2DBLCLK or WM_CHAR.
WinPopupMenu requires that you specify the pop-up menu's handle and also the handles of the parent and owner windows of the pop-up menu. WinLoadMenu and WinCreateMenu return the handle of the pop-up menu window, but you must obtain the handles of the parent and owner by using WinQueryWindow.
You determine the position of the pop-up menu in relation to its parent by specifying coordinates and style flags in WinPopupMenu. The x and y coordinates determine the position of the lower-left corner of the menu relative to the lower-left corner of the parent. The system may adjust this position, however, if you include the PU_HCONSTRAIN or PU_VCONSTRAIN style flags in the call to WinPopupMenu. If necessary, PU_HCONSTRAIN adjusts the horizontal position of the menu so that its left and right edges are within the borders of the desktop window. PU_VCONSTRAIN makes the same adjustments vertically. Without these flags, a desktop-level pop-up menu can lie partially off the screen, with some items not visible nor selectable.
The PU_POSITIONONITEM flag also can affect the position of the pop-up menu. This flag positions the pop-up menu so that, when the pop-up menu appears, the specified item lies directly under the mouse pointer. Also, PU_POSITIONONITEM automatically selects the item. PU_POSITIONONITEM is useful for placing the current menu selection under the pointer so that, if the user releases the mouse button without selecting a new item, the current selection remains unchanged.
The PU_SELECTITEM flag is similar to PU_POSITIONONITEM except that it just selects the specified item; it does not affect the position of the menu.
You can enable the user to choose an item from a pop-up menu by using the same mouse button that was used to display the menu. To do this, specify the PU_MOUSEBUTTONn flag, where n corresponds to the mouse button used to display the menu. This flag specifies the mouse buttons for the user to interact with a pop-up menu once it is displayed.
By using the PU_MOUSEBUTTONn flag, you can enable the user to display the pop-up menu, select an item, and dismiss the menu, all in one operation. For example, if your window procedure displays the pop-up window when the user double-clicks mouse button 2, specify the PU_MOUSEBUTTON2DOWN flag in the WinPopupMenu function. Then, the user can display the menu with mouse button 2; and, while holding the button down, select an item. When the user releases the button, the item is chosen and the menu dismissed.
System Menu
The system menu in the upper-left corner of a standard frame window is different from the menus defined by the application. The system menu is controlled and defined almost exclusively by the system; your only decision about it is whether to include it when creating a frame window. (It is unusual for a frame window not to include a system menu.) The system menu generates WM_SYSCOMMAND messages instead of WM_COMMAND messages. Most applications simply use the default behavior for WM_SYSCOMMAND messages, although applications can add, delete, and change system-menu entries.
Menu Items
All menus can contain two main types of menu items: command items and submenu items. When the user chooses a command item, the menu immediately posts a message to the parent window. When the user selects a submenu item, the menu displays a submenu from which the user may choose another item. Since a submenu window also can contain a submenu item, submenus can originate from other submenus.
When the user chooses a command item from a menu, the menu system posts a WM_COMMAND, WM_SYSCOMMAND, or WM_HELP message to the owner window, depending on the style bits of the menu item.
Applications can change the attributes, style, and contents of menu items, and insert and delete items at run time, to reflect changes in the command environment. An application also can add items to or delete items from the menu bar, a pop-up menu, or a submenu. For example, an application might maintain a menu of the fonts currently available in the system. This application would use graphics programming interface (GPI) calls to determine which fonts were available and, then, insert a menu item for each font into a submenu. Furthermore, the application might set the check-mark attribute of the menu item for the currently chosen font. When the user chose a new font, the application would remove the check-mark attribute from the previous choice and add it to the new choice.
The Help Item
To present a standard interface to the novice user, all applications must have a Help item in their menu bars. The Help item is defined with a particular style, attributes, and position in the menu. When the user chooses the Help item, the menu posts a WM_HELP message to the owner window, enabling the application to respond appropriately.
The item should read Help, have an identifier of 0, and have the MIS_BUTTONSEPARATOR or MIS_HELP item styles. The Help menu item should be the last item in the menu template, so that it is displayed as the rightmost item in the menu bar.
If an application uses the system default accelerator table, the user can select the Help item using either a mouse or the F1 key.
Menu-Item Styles
All menu items have a combination of style bits that determine what kind of data the item contains and what kind of message it generates when the user selects it. For example, a menu item can have the MIS_TEXT, MIS_BITMAP, or other styles that specify the visual representation of the menu item on the screen. Other styles determine what kinds of messages the item sends to its owner and whether the owner draws the item. Menu-item styles typically do not change during program execution, but you can query and set them dynamically by sending MM_QUERYITEM and MM_SETITEM messages with the menu-item identifier to the menu-bar window. For text menu items (MIS_TEXT), an MM_SETITEMTEXT message sets the text. The MM_QUERYITEMTEXT message queries the text of the item. For non-text menu items, the hItem field of the MENUITEM structure typically contains the handle of a display object, such as a bit-map handle for MIS_BITMAP menu items.
An application can draw a menu item by setting the style MIS_OWNERDRAW for the menu item. This usually is done by specifying the MIS_OWNERDRAW style for the menu item in the resource-definition file; but it also can be done at run time. When the application draws a menu item, it must respond to messages from the menu each time the item must be drawn.
Menu-Item Attributes
Menu items have attributes that determine how the items are displayed and whether or not the user can choose them. An application can set and query menu-item attributes by sending MM_SETITEMATTR and MM_QUERYITEMATTR messages, with the menu-item identifier, to the menu-bar window. If the specified item is in a submenu, there are two methods of determining its attributes. The first is to send MM_SETITEMATTR and MM_QUERYITEMATTR messages to the top-level menu, specifying the identifier of the item and setting a flag so that the message searches all submenus for the item. Then, you can retrieve the handle of the menu-bar by calling WinWindowFromID, with the handle of the frame window and the FID_MENU frame-control identifier.
The second method, which is more efficient if you want to either work with more than one submenu item or set the same item several times, involves two steps:
- Send an MM_QUERYITEM message to the menu, with the identifier of the submenu. The updated MENUITEM structure contains the window handle of the submenu.
- Send an MM_QUERYITEMATTR (or MM_SETITEMATTR) message to the submenu window, specifying the identifier of the item in the submenu.
Menu-Item Structure
A single menu item is defined by the MENUITEM data structure. This structure is used with the MM_INSERTITEM message to insert items in a menu or to query and set item characteristics with the MM_QUERYITEM and MM_SETITEM messages. The MENUITEM structure has the following form:
typedef struct _MENUITEM { /* mi */ SHORT iPosition; USHORT afStyle; USHORT afAttribute; USHORT id; HWND hwndSubMenu; ULONG hItem; } MENUITEM;
You can derive the values of most of the fields in this structure directly from the resource-definition file. However, the last field in the structure, hItem, depends on the style of the menu item.
The iPosition field specifies the ordinal position of the item within its menu window. If the item is part of the menu bar, iPosition specifies its relative left-to-right position, with 0 being the leftmost item. If the item is part of a submenu, iPosition specifies its relative top-to-bottom and left-to-right positions, with 0 being the upper-left item. An item with the MIS_BREAKSEPARATOR style in a pull-down menu causes a new column to begin.
The afStyle field contains the style bits of the item. The afAttribute field contains the attribute bits.
The id field contains the menu-item identifier. The identifier should be unique but does not have to be. Just remember that, when multiple items have the same identifier, they post the same command number in the WM_COMMAND, WM_SYSCOMMAND, and WM_HELP messages. Also, any message that specifies a menu item with a non-unique identifier will find the first item that has that identifier.
The hwndSubMenu field contains the window handle of a submenu window (if the item is a submenu item). The hwndSubMenu field is NULL for command items.
The hItem field contains a handle to the display object for the item, unless the item has the MIS_TEXT style, in which case, hItem is 0. For example, a menu item with the MIS_BITMAP style has an hItem field that is equal to its bit-map handle.
Menu Access
The OS/2 operating system is designed to work with or without a mouse or other pointing device. The system provides default behavior that enables a user to interact with menus without a mouse. Following are the keystrokes that produce this default behavior:
Keystroke | Action |
---|---|
Alt | Toggles in and out of menu-bar mode. |
Alt+Spacebar | Shows the system menu. |
F10 | Backs up one level. If a submenu is displayed, it is canceled. If no submenu is displayed, this keystroke exits the menu. |
Shift+Esc | Shows the system menu. |
Right Arrow | Cycles to the next top-level menu item. If the selected item is at the far-left side of the menu, the menu code sends a WM_NEXTMENU message to the frame window. The default processing by the frame window is to cycle between the application and system menus. (An application can modify this behavior by subclassing the frame window.) If the selected item is in a submenu, the next column in the submenu is selected, or the next top-level menu item is selected; this keystroke also can send or process a WM_NEXTMENU message. |
Left Arrow | Works like the Right Arrow key, except in the opposite direction. In submenus, this keystroke backs up one column, except when the currently selected item is in the far-left column, in which case the previous submenu is selected. |
Up Arrow or Down Arrow | When pressed in a top-level menu, activates a submenu. When pressed in a submenu, this keystroke selects the previous or next item, respectively. |
Enter | Activates a submenu, and highlights the first item if an item has a submenu associated with it; otherwise, this keystroke chooses the item as though the user released the mouse button while the item was selected. |
Alphabetic character | Selects the first menu item with the specified character as its mnemonic key. A mnemonic is defined for a menu item by placing a tilde (~) before the character in the menu text. If the selected item has a submenu associated with it, the menu is displayed, and the first item is highlighted; otherwise, the item is chosen. |
An application does not support the default keyboard behavior with any unusual code; instead, the application receives a message when a menu item is chosen by the keyboard just as though it had been chosen by a mouse.
Mnemonics
Adding mnemonics to menu items is one way of providing the user with keyboard access to menus. You can indicate a mnemonic keystroke for a menu item by preceding a character in the item text with a tilde, as in ~File. Then, the user can choose that item by pressing the mnemonic key when the menu is active.
The menu bar is active when the user presses and releases the Alt key, and the first item in the menu bar is highlighted. A pop-up or pull-down menu is active when it is open.
Accelerators
In addition to mnemonics, a menu item can have an associated keyboard accelerator. Accelerators are different from mnemonics in that the menu need not be active for the accelerator key to work. If you have associated a menu item with a keyboard accelerator, display the accelerator to the right of the menu item. Do this in the resource-definition file by placing a tab character (\t
) in the menu text before the characters that will be displayed on the right. For example, if the Close item had the F3 function key as its keyboard accelerator, the text for the item would be Close\tF3
.
Using Menus
This section explains how to perform the following tasks:
- Define menu items in a resource file
- Include a menu bar in a standard window
- Create a pop-up menu
- Add a menu to a dialog window
- Access the system menu
- Respond to a the menu choice of a user
- Set and query menu-item attributes
- Add and delete menu items
- Create a custom menu item
Defining Menu Items in a Resource File
Typically, a menu resource represents the menu bar or pop-up menu and all the related submenus. A menu-item definition is organized as shown in the following code:
MENUITEM item text, item identifier, item style, item attributes
The menu resource-definition file specifies the text of each item in the menu, its unique identifier, its style and attributes, and whether it is a command item or a submenu item. A menu item that has no specification for style or attributes has the default style of MIS_TEXT and all attribute bits off, indicating that the item is enabled. The MIS_SEPARATOR style identifies nonselectable lines between menu items. The following figure is sample Resource Compiler source code that defines a menu resource. The code defines a menu with three submenu items in the menu bar (File, Edit, and Font) and a command item (Help). Each submenu has several command items, and the Font submenu has two other submenus within it.
MENU ID_MENU_RESOURCE BEGIN SUBMENU "~File", IDM_FILE BEGIN MENUITEM "~Open...", IDM_FI_OPEN MENUITEM "~Close\tF3", IDM_FI_CLOSE, 0, MIA_DISABLED MENUITEM "~Quit", IDM_FI_QUIT MENUITEM "", IDM_FI_SEP1, MIS_SEPARATOR MENUITEM "~About Sample", IDM_FI_ABOUT END SUBMENU "~Edit", IDM_EDIT BEGIN MENUITEM "~Undo", IDM_ED_UNDO, 0, MIA_DISABLED MENUITEM "", IDM_ED_SEP1, MIS_SEPARATOR MENUITEM "~Cut", IDM_ED_CUT MENUITEM "C~opy", IDM_ED_COPY MENUITEM "~Paste", IDM_ED_PASTE MENUITEM "C~lear", IDM_ED_CLEAR END SUBMENU "Font", IDM_FONT BEGIN SUBMENU "Style", IDM_FONT_STYLE BEGIN MENUITEM "Plain", IDM_FONT_STYLE_PLAIN MENUITEM "Bold", IDM_FONT_STYLE_BOLD MENUITEM "Italic", IDM_FONT_STYLE_ITALIC END SUBMENU "Size", IDM_FONT_SIZE BEGIN MENUITEM "10", IDM_FONT_SIZE_10 MENUITEM "12", IDM_FONT_SIZE_12 MENUITEM "14", IDM_FONT_SIZE_14 END END MENUITEM "F1=Help", 0x00, MIS_TEXT | MIS_BUTTONSEPARATOR | MIS_HELP END
To define a menu item with the MIS_BITMAP style, an application must use a tool such as Icon Editor to create a bit map, include the bit map in its resource-definition file, and define a menu in the file (as shown in the following figure). The text for the bit map menu items is an ASCII representation of the resource identifier of the bit map resource to be displayed for that item.
/* Bring externally created bit maps into the resource file. */ BITMAP 101 button.bmp BITMAP 102 hirest.bmp BITMAP 103 hizoom.bmp BITMAP 104 hired.bmp /* Connect a menu item with a bit map. */ SUBMENU "~Bitmaps", IDM_BITMAP BEGIN MENUITEM "#101", IDM_BM_01, MIS_BITMAP MENUITEM "#102", IDM_BM_02, MIS_BITMAP MENUITEM "#103", IDM_BM_03, MIS_BITMAP MENUITEM "#104", IDM_BM_04, MIS_BITMAP END
Including a Menu Bar in a Standard Window
If you have defined a menu resource in a resource-definition file, you can use the menu resource to create a menu bar in a standard window. You include the menu bar by using the FCF_MENU attribute flag and specifying the menu-resource identifier in a call to WinCreateStdWindow, as shown in the following code fragment:
#define ID_MENU_RESOURCE 100 HWND hwndFrame; CHAR szClassName[]="MyClass"; CHAR szTitle[]="My Title"; ULONG flControlStyle = FCF_MENU | FCF_SIZEBORDER | FCF_TITLEBAR | FCF_ACCELTABLE; hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE, &flControlStyle, szClassName, szTitle, 0, (HMODULE) NULL, ID_MENU_RESOURCE, NULL);
After you make this call, the operating system automatically includes the menu in the window, drawing the menu bar across the top of the window. When the user chooses an item from the menu, the menu posts the message to the frame window. The frame window passes any WM_COMMAND messages to the client window. (The frame window does not pass WM_SYSCOMMAND messages to the client window.) WM_HELP messages are posted to the focus window. The WinDefWindowProc function passes WM_HELP messages to the parent window. If a WM_HELP message is passed to a frame window, the frame window calls the HK_HELP hook. Your client window procedure must process these messages to respond to the user's actions.
Creating a Pop-up Menu
The following code fragment shows how to make a pop-up menu appear when the user double-clicks mouse button 2 anywhere in the parent window. The menu is positioned with the mouse pointer located on the item having the IDM_OPEN identifier and is constrained horizontally and vertically. Then, the user can select an item from the pop-up menu using mouse button 2.
#define ID_MENU_RESOURCE 110 #define IDM_OPEN 120 HWND hwndFrame; MRESULT ClientWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { HWND hwndMenu; BOOL fSuccess; switch (msg) { . . /* Process other messages. */ . case WM_BUTTON2DBLCLK: hwndMenu = WinLoadMenu(hwnd, (HMODULE) NULL, ID_MENU_RESOURCE); fSuccess = WinPopupMenu(hwnd, hwndFrame, hwndMenu, 20, 50, IDM_OPEN, PU_POSITIONONITEM | PU_HCONSTRAIN | PU_VCONSTRAIN | PU_MOUSEBUTTON2DOWN | PU_MOUSEBUTTON2); . . .