11.18.5.5 - Пример использования пользовательских точечных рисунков значков "галочки ".

Пример в этой теме связывает пользовательские точечные рисунки (значки) типа "галочки" с пунктами меню в двух меню. Пункты меню в первом меню определяют атрибуты символа: полужирный, курсивный, и подчеркивание. Каждый пункт меню может быть или отмечен или не отмечен "галочкой". Для этих пунктов меню пример использует значки "галочки ", которые похожи на маркеры установки и сброса состояния проверки органа управления.

Пункты меню во втором меню определяют параметры настройки выравнивания параграфа: слева, по центру и справа. Только один из этих пунктов меню в одно и тоже данное время может быть отмечен "галочкой". Для этих пунктов меню, пример использует значки, которые похожи на установленную и снятую метки типа радио-кнопки органа управления.

Оконная процедура обрабатывает сообщение WM_CREATE путем вызова определяемой программой функции OnCreate. OnCreate создает четыре значка "галочки", а затем связывает их со своими соответствующими пунктами меню при помощи использования функции SetMenuItemBitmaps.

Чтобы создать каждый значок, OnCreate вызывает определяемую программой функцию CreateMenuBitmaps, устанавливая указатель на конкретную функцию рисования для значка. Функция CreateMenuBitmaps создает одноцветный значок требуемого размера, выбирает его в памяти контекста устройства и стирает фон. Затем она вызывает заданную функцию рисования, чтобы заполнить передний план картинки.

Имеется четыре определяемые программой функции рисования - DrawCheck, DrawUncheck, DrawRadioCheck и DrawRadioUncheck. Они рисуют прямоугольник с X (крестиком), пустой прямоугольник, эллипс, содержащий меньший затемненный эллипс и, соответственно, пустой эллипс.

Оконная процедура обрабатывает сообщение WM_DESTROY, удаляя значки типа "галочки". Она получает дескриптор каждый картинки при помощи использования функции GetMenuItemInfo, а затем переправляет дескриптор функции DeleteObject.

Когда пользователь выбирает пункт меню, окну владельцу отправляется сообщение WM_COMMAND. Для пунктов меню в меню Character, оконная процедура вызывает определяемую программой функцию CheckCharacterItem. Для пунктов в меню Paragraph, оконная процедура вызывает определяемую программой функцию CheckParagraphItem.

Каждый пункт в меню Character, независимо друг от друга, может быть отмечен или не отмечен значком типа "галочки". Следовательно, CheckCharacterItem просто включает состояние проверки ("галочки") определяемого пункта меню. Сначала функция вызывает функцию GetMenuItemInfo, чтобы получить текущее состояние пункта меню. Затем она включает флажок состояния MFS_CHECKED и устанавливает новое состояние путем вызова функции SetMenuItemInfo.

В отличие от атрибутов символа, одновременно может быть выбрано только одно выравнивание абзаца. Следовательно, CheckParagraphItem отмечает "галочкой" определяемый пункт меню и удаляет галочку из всех других пунктов в меню. Чтобы сделать это, она вызывает функцию CheckMenuRadioItem.

Ниже следуют необходимые части заголовочного файла прикладной программы.

// Идентификаторы пунктов меню для меню Character

#define IDM_CHARACTER 10
#define IDM_BOLD      11
#define IDM_ITALIC    12
#define IDM_UNDERLINE 13

// Идентификаторы пункта меню для меню Paragraph

#define IDM_PARAGRAPH 20
#define IDM_LEFT      21
#define IDM_CENTER    22
#define IDM_RIGHT     23

// Тип указателя функции для функций рисования

typedef VOID (WINAPI * DRAWFUNC)(HDC hdc, SIZE size);

Ниже следуют необходимые части оконной процедуры прикладной программы и зависимых функций.

LRESULT CALLBACK MainWindowProc(
        HWND hwnd,
        UINT uMsg,
        WPARAM wParam,
        LPARAM lParam
        )
{
    switch (uMsg) {
        case WM_CREATE:
            if (!OnCreate(hwnd))
                return -1;
            break;

        case WM_DESTROY:
            OnDestroy(hwnd);
            PostQuitMessage(0);
            break;

        case WM_COMMAND:
            switch (LOWORD(wParam)) {

                case IDM_BOLD:

                case IDM_ITALIC:

                case IDM_UNDERLINE:
                    CheckCharacterItem(hwnd, LOWORD(wParam));
                    break;

                case IDM_LEFT:
                case IDM_CENTER:
                case IDM_RIGHT:
                    CheckParagraphItem(hwnd, LOWORD(wParam));
                    break;

                .
                . // Обработка других команд здесь.
                .

            }

            break;

        .
        . // Обработка других сообщений здесь.
        .

        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

VOID WINAPI CheckCharacterItem(HWND hwnd, UINT uID)
{
    HMENU hmenuBar = GetMenu(hwnd);
    HMENU hmenuPopup;
    MENUITEMINFO mii;

    // Получим дескриптор меню Character.

    mii.fMask = MIIM_SUBMENU;  // информация, которую получаем
    GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);

    hmenuPopup = mii.hSubMenu;

    // Получим состояние заданного пункта меню.

    mii.fMask = MIIM_STATE;    // информация, которую получаем
    GetMenuItemInfo(hmenuPopup, uID, FALSE, &mii);

    // Переключим состояние отметки типа «галочки».

    mii.fState ^= MFS_CHECKED;
    SetMenuItemInfo(hmenuPopup, uID, FALSE, &mii);
}

VOID WINAPI CheckParagraphItem(HWND hwnd, UINT uID)
{
    HMENU hmenuBar = GetMenu(hwnd);
    HMENU hmenuPopup;
    MENUITEMINFO mii;

    // Получим дескриптор меню Paragraph.

    mii.fMask = MIIM_SUBMENU; // информация, которую получаем
    GetMenuItemInfo(hmenuBar, IDM_PARAGRAPH, FALSE, &mii);
    hmenuPopup = mii.hSubMenu;

    // Отметим "галочкой" определяемый пункт и снимем отметку "галочкой" со всех других.

    CheckMenuRadioItem(
            hmenuPopup,         	// дескриптор меню
            IDM_LEFT,           	// первый пункт в ряду
            IDM_RIGHT,          	// последний пункт в ряду
            uID,                	// пункт для проверки
            MF_BYCOMMAND        	// ID, нет позиции
            );
}

BOOL WINAPI OnCreate(HWND hwnd)
{
    HMENU hmenuBar = GetMenu(hwnd);
    HMENU hmenuPopup;
    MENUITEMINFO mii;
    UINT uID;
    HBITMAP hbmChecked;
    HBITMAP hbmUnchecked;

    // Получим дескриптор меню Character.

    mii.fMask = MIIM_SUBMENU; // информация, которую получаем
    GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);
    hmenuPopup = mii.hSubMenu;

    // Создадим значки отметки "галочкой" и снятие отметки.

    hbmChecked = CreateMenuBitmap(DrawCheck);
    hbmUnchecked = CreateMenuBitmap(DrawUncheck);

    // Установим точечные рисунки (значки) пометок для каждого пункта меню.

    for (uID = IDM_BOLD; uID <= IDM_UNDERLINE; uID++) {
        SetMenuItemBitmaps(hmenuPopup, uID, MF_BYCOMMAND,
                hbmUnchecked, hbmChecked);
    }

    // Получим дескриптор выскакивающего меню Paragraph.

    mii.fMask = MIIM_SUBMENU; // информация, которую получаем

    GetMenuItemInfo(hmenuBar, IDM_PARAGRAPH, FALSE, &mii);
    hmenuPopup = mii.hSubMenu;

    // Создадим значки отметки "галочкой" и снятие отметки.

    hbmChecked = CreateMenuBitmap(DrawRadioCheck);
    hbmUnchecked = CreateMenuBitmap(DrawRadioUncheck);

    // Установим точечные рисунки (значки) пометки для каждого пункта меню.

    for (uID = IDM_LEFT; uID <= IDM_RIGHT; uID++) {
        SetMenuItemBitmaps(hmenuPopup, uID, MF_BYCOMMAND,
                hbmUnchecked, hbmChecked);

    }

    // Вначале отметим "галочкой) IDM_LEFT пункт параграфа.

    CheckMenuRadioItem(hmenuPopup, IDM_LEFT, IDM_RIGHT,
            IDM_LEFT, MF_BYCOMMAND);
    return TRUE;
}

HBITMAP WINAPI CreateMenuBitmap(DRAWFUNC lpfnDraw)
{
    // Создадим DC совместимый с DC рабочего стола окна.

    HWND hwndDesktop = GetDesktopWindow();
    HDC hdcDesktop = GetDC(hwndDesktop);
    HDC hdcMem = CreateCompatibleDC(hdcDesktop);

    // Установим требуемый растровый размер.


    DWORD dwExt = GetMenuCheckMarkDimensions();
    SIZE size = { LOWORD(dwExt), HIWORD(dwExt) };

    // Создадим одноцветный значок и выберем его.

    HBITMAP hbm = CreateBitmap(size.cx, size.cy, 1, 1, NULL);
    HBITMAP hbmOld = SelectObject(hdcMem, hbm);

    // Очистим фон и вызовем функцию рисования.

    PatBlt(hdcMem, 0, 0, size.cx, size.cy, WHITENESS);
    (*lpfnDraw)(hdcMem, size);

    // Навести порядок.

    SelectObject(hdcMem, hbmOld);

    DeleteDC(hdcMem);
    ReleaseDC(hwndDesktop, hdcDesktop);
    return hbm;
}

VOID WINAPI DrawCheck(HDC hdc, SIZE size)
{
    HBRUSH hbrOld;
    hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));
    Rectangle(hdc, 0, 0, size.cx, size.cy);
    MoveToEx(hdc, 0, 0, NULL);
    LineTo(hdc, size.cx, size.cy);
    MoveToEx(hdc, 0, size.cy - 1, NULL);
    LineTo(hdc, size.cx - 1, 0);
    SelectObject(hdc, hbrOld);
}

VOID WINAPI DrawUncheck(HDC hdc, SIZE size)

{
    HBRUSH hbrOld;
    hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));
    Rectangle(hdc, 0, 0, size.cx, size.cy);
    SelectObject(hdc, hbrOld);
}

VOID WINAPI DrawRadioCheck(HDC hdc, SIZE size)
{
    HBRUSH hbrOld;
    hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));
    Ellipse(hdc, 0, 0, size.cx, size.cy);
    SelectObject(hdc, GetStockObject(BLACK_BRUSH));
    Ellipse(hdc, 2, 2, size.cx - 2, size.cy - 2);
    SelectObject(hdc, hbrOld);

}

VOID WINAPI DrawRadioUncheck(HDC hdc, SIZE size)
{
    HBRUSH hbrOld;
    hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));
    Ellipse(hdc, 0, 0, size.cx, size.cy);
    SelectObject(hdc, hbrOld);
}

VOID WINAPI OnDestroy(HWND hwnd)
{
    HMENU hmenuBar = GetMenu(hwnd);
    HMENU hmenuPopup;
    MENUITEMINFO mii;

    // Получим дескриптор меню Character.

    mii.fMask = MIIM_SUBMENU; // информация, которую получаем
    GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);

    hmenuPopup = mii.hSubMenu;

    // Получим точечные рисунки (значки) "галочки " и удалим их.

    mii.fMask = MIIM_CHECKMARKS;
    GetMenuItemInfo(hmenuPopup, IDM_BOLD, FALSE, &mii);
    DeleteObject(mii.hbmpChecked);
    DeleteObject(mii.hbmpUnchecked);

    // Получим дескриптор меню Paragraph.

    mii.fMask = MIIM_SUBMENU; // информация, которую получаем
    GetMenuItemInfo(hmenuBar, IDM_PARAGRAPH, FALSE, &mii);
    hmenuPopup = mii.hSubMenu;

    // Получим точечные рисунки (значки) "галочки " и удалим их.


    mii.fMask = MIIM_CHECKMARKS;
    GetMenuItemInfo(hmenuPopup, IDM_LEFT, FALSE, &mii);
    DeleteObject(mii.hbmpChecked);
    DeleteObject(mii.hbmpUnchecked);
}


Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Владимир Соковиков - 08.10.2002