Applications can customize the appearance of an individual menu item by setting the MIS_OWNERDRAW style bit for the item. The operating system sends two different messages to an application that include owner-drawn menu items: WM_MEASUREITEM and WM_DRAWITEM. Both messages include a pointer to an OWNERITEM data structure.

WM_MEASUREITEM is sent only once for each owner-drawn item when the menu is initialized. The message is sent to the owner of the menu (typically, a frame window), which forwards the message to its client window. Typically, the client window procedure processes WM_MEASUREITEM by filling in the yTop and Right fields of the RECTL structure, specified by the rclItem field of this OWNERITEM structure; this specifies the size of the rectangle needed to enclose the item when it is drawn. The following code fragment responds to a WM_MEASUREITEM message.

    case WM_MEASUREITEM:
        ((POWNERITEM) mp2)->rclItem.xRight = 26;
        ((POWNERITEM) mp2)->rclItem.yTop = 10;
        return 0;

If a menu item has the MIS_OWNERDRAW style, the owner window receives a WM_DRAWITEM message every time the menu item needs to be drawn. You process this message by using the hps and rclItem fields of the OWNERITEM structure to draw the item. There are two situations in which the owner window receives a WM_DRAWITEM message:

You can choose to handle one or both of these situations. Typically, you handle the drawing of the item. You may not want to handle the second situation, however, since the system-default behavior (inverting the bits in the item rectangle) often is acceptable. The two situations in which a WM_DRAWITEM message is received are detected by comparing the values of the fsState and fsStateOld fields of the OWNERITEM structure that is sent as part of the message. If the two fields are the same, draw the item. Before drawing the item, however, check its attributes to see whether it has the attributes MIA_CHECKED, MIA_FRAMED, or MIA_DISABLED. Then draw the item according to the attributes.

For example, when the checked attribute of an owner-drawn menu item changes, the system sends a WM_DRAWITEM message to the item so that it can redraw itself and either draw or remove the check mark. If you want the system-default check mark, simply draw the item and leave the fsAttribute and fsAttributeOld fields unchanged; the system draws the check mark if necessary. If you draw the check mark yourself, clear the MIA_CHECKED bit in both fsAttribute and fsAttributeOld so that the system does not attempt to draw a check mark.

In the same example, if fsAttribute and fsAttributeOld are not equal, the highlight showing that an item is selected needs to change. The MIA_HILITED bit of the fsAttribute field is set if the item needs to be highlighted and is not set if the highlight needs to be removed. If you do not want to provide your own highlighting, you should ignore any WM_DRAWITEM message in which fsAttribute and fsAttributeOld are not equal. If you do not alter these two fields, the system performs its default highlighting operation. If you want to provide your own visual cue that an item is selected, respond to a WM_DRAWITEM message in which the fsAttribute and fsAttributeOld fields are not equal by providing the cue and clearing the MIA_HILITED bit of both fields before returning from the message.

Likewise, the MIA_CHECKED and MIA_FRAMED bits of fsAttribute and fsAttributeOld either can be used to perform the corresponding action or passed on, unchanged, so that the system performs the action. The following code fragment shows how to respond to a WM_DRAWITEM message when you want to draw the item and also be responsible for its highlighted state.

    case WM_DRAWITEM:
        {
        POWNERITEM poi;
        RECTL      rcl;
        MPARAM     mp2;

        poi = (POWNERITEM) mp2;

        /*
         * If the new attribute equals the old attribute,
         * redraw the entire item.
         */

        if (poi->fsAttribute == poi->fsAttributeOld) {

            /*
             * Draw the item in poi->hps and poi->rclItem, and check the
             * attributes for check marks. If you produce your own check marks,
             * use this line of code:
             *
             *     poi->fsAttributeOld = (poi->fsAttribute &= ~MIA_CHECKED;
             */

        }

        /* Else highlight the item or remove its highlight. */

        else if ((poi->fsAttribute & MIA_HILITED) !=
                (poi->fsAttributeOld & MIA_HILITED)) {

            /*
             * Set bits the same so that the menu window does not highlight
             * the item or remove its highlight.
             */

            poi->fsAttributeOld = (poi->fsAttribute &= ~MIA_HILITED);
        }
        return TRUE; /* TRUE means the item is drawn. */
        } /* endcase */

Responding to WM_DRAWITEM Message


[Back] [Next]