Управление состоянием элементов меню
Следующая функция изменяет состояние элемента меню hMenu:
BOOL SetMenuItemInfo( MENU hMenu, UINT uItem,
BOOL fByPosition, LPMENUITEMINFO lpmii);
При fByPosition = FALSE значение uItem равно идентификатору команды элемента, иначе – позиции элемента в меню. Значение lpmii указывает на структуру типа MENUITEMINFO, которая уже содержит новые данные для элемента. В случае успешного выполнения функция возвращает ненулевое значение.
Проанализируем вызов функции SetMenuItemInfo. Первые 3 аргумента указывают на элемент, параметры которого изменяют. Последний аргумент содержит параметры нового состояния элемента. При этом изменяют те параметры, на которые указывает поле fMask.
Задача. Описать функцию для изменения состояния элемента.
Следующая функция является примером решения данной задачи:
BOOL SetMenuItem(HMENU hMenu, UINT uIns, UINT fState, BOOL flag)
{
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_STATE | MIIM_ID;
mii.fState = fState;
mii.wID = uIns;
return SetMenuItemInfo( hMenu, uIns, flag, &mii);
}
Список формальных параметров этой функции:
1. hMenu – дескриптор меню, состояние элемента которого нужно изменить.
2. uIns и flag совпадают соответственно с параметрами uItem и fByPosition, функции SetMenuItemInfo.
3. fState задает новое состояние элемента.
4. Поле fMask указывает, что у элемента изменяется только значение поля fState. А поле wID структуры mii операционная система использует для получения указания на изменяемый элемент.
Следующая функция выбирает данные элемента меню hMenu:
BOOL GetMenuItemInfo (HMENU hMenu, UINT uItem,
BOOL fByPosition, LPMENUITEMINFO lpmii);
При fByPosition = FALSE значение uItem равно идентификатору команды элемента, иначе – позиции элемента в меню. Значение lpmii указывает на структуру типа MENUITEMINFO, поле fMask которой содержит указания на запрашиваемые параметры. В эту же структуру будут записаны значения запрошенных параметров элемента. В случае успешного выполнения функция возвращает ненулевое значение.
Задача. Описать функцию для запроса состояния элемента.
Следующая функция является примером решения данной задачи:
UINT GetMenuItem(HMENU hMenu, UINT uIns, BOOL flag)
{
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_STATE;
GetMenuItemInfo(hMenu, uIns, flag, &mii);
return mii.fState;
}
Список формальных параметров этой функции:
1. hMenu – дескриптор меню, состояние элемента которого нужно запросить.
2. uIns и flag совпадают соответственно с параметрами uItem и fByPosition функции GetMenuItemInfo.
Функция возвращает значение состояния элемента. Поле fMask указывает, что запрашивается только значение поля fState элемента.
Задача. Главное меню изначально содержит раздел "Файлы" со строками "Открыть", "Сохранить" и "Выход". Причем строка "Сохранить" заблокирована. При выборе строки "Открыть" заблокировать ее, разблокировать строку "Сохранить" и вставить разделы "Правка" и "Вид" в главное меню.
При выборе строки "Правка" отображается временное меню со строками "Найти" и "Заменить". Причем эти строки при их выборе должны быть отмечены как независимые флажки.
При выборе строки "Вид" отображается временное меню со строками "Обычный" и "Структура". Причем эти строки при их выборе должны быть отмечены как зависимые переключатели.
При выборе строки "Сохранить" заблокировать ее. Затем разблокировать строку "Открыть" и из главного меню удалить разделы "Правка" и "Вид".
Листинг 4.3. Управление состоянием строк меню
#include <windows.h>
#define CM_FILE_OPEN 1001
#define CM_FILE_SAVE 1002
#define CM_FILE_QUIT 1003
#define CM_EDIT_FIND 2001
#define CM_EDIT_REPLC 2002
#define CM_VIEW_NORM 3001
#define CM_VIEW_STRC 3002
BOOL RegClass(WNDPROC, LPCTSTR, UINT);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInstance;
TCHAR szClass[] = TEXT("SetMenuInfo");
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)
{
MSG msg;
HWND hwnd;
hInstance = hInst;
if (!RegClass(WndProc, szClass, COLOR_WINDOW)) return FALSE;
hwnd = CreateWindow(szClass, TEXT("Управление состоянием элементов меню"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, NULL);
if (!hwnd) return FALSE;
while(GetMessage(&msg, 0, 0, 0))
{ TranslateMessage(&msg); DispatchMessage(&msg); }
return msg.wParam;
}
BOOL RegClass(WNDPROC Proc, LPCTSTR szName, UINT brBackground)
{
WNDCLASS wc;
wc.style = wc.cbClsExtra = wc.cbWndExtra = 0;
wc.lpfnWndProc = Proc;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(brBackground +1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szName;
return (RegisterClass(&wc) != 0);
}
BOOL SetMenuItem(HMENU hMenu, UINT uIns, UINT fState, BOOL flag)
{
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_STATE | MIIM_ID;
mii.fState = fState;
mii.wID = uIns;
return SetMenuItemInfo( hMenu, uIns, flag, &mii);
}
UINT GetMenuItem(HMENU hMenu, UINT uIns, BOOL flag)
{
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_STATE;
GetMenuItemInfo(hMenu, uIns, flag, &mii);
return mii.fState;
}
BOOL CreateMenuItem(HMENU hMenu, TCHAR *str, UINT uIns, UINT uCom, HMENU hSubMenu, BOOL flag, UINT fType)
{
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_STATE | MIIM_TYPE | MIIM_SUBMENU | MIIM_ID;
mii.fType = fType;
mii.fState= MFS_ENABLED;
mii.dwTypeData = str;
mii.cch = sizeof(str);
mii.wID = uCom;
mii.hSubMenu = hSubMenu;
return InsertMenuItem(hMenu, uIns, flag, &mii);
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HMENU hMainMenu, hFileMenu, hEditMenu, hViewMenu;
switch (msg)
{
case WM_CREATE:
{
hMainMenu = CreateMenu();
//Создаем временное меню для раздела "Файлы"
hFileMenu = CreatePopupMenu();
int i=0; //Инициализация позиции в меню hFileMenu
CreateMenuItem( hFileMenu, TEXT("&Открыть"), i++, CM_FILE_OPEN, NULL, FALSE, MFT_STRING);
CreateMenuItem( hFileMenu, TEXT("&Сохранить"), i++, CM_FILE_SAVE, NULL, FALSE, MFT_STRING);
CreateMenuItem( hFileMenu, NULL, i++, 0, NULL, FALSE, MFT_SEPARATOR);
CreateMenuItem( hFileMenu, TEXT("&Выход"), i++, CM_FILE_QUIT, NULL, FALSE, MFT_STRING);
//Создаем временное меню для раздела "Правка"
hEditMenu = CreatePopupMenu();
i=0; //Инициализация позиции в меню hEditMenu
CreateMenuItem( hEditMenu, TEXT("&Найти"), i++, CM_EDIT_FIND, NULL, FALSE, MFT_STRING );
CreateMenuItem( hEditMenu, TEXT("&3аменить"), i++, CM_EDIT_REPLC, NULL, FALSE, MFT_STRING);
//Создаем временное меню для раздела "Вид"
hViewMenu = CreatePopupMenu();
i=0; //Инициализация позиции в меню hViewMenu
CreateMenuItem( hViewMenu, TEXT("&Обычный"), i++, CM_VIEW_NORM, NULL, FALSE, MFT_RADIOCHECK);
CreateMenuItem( hViewMenu, TEXT("&Структура"), i++, CM_VIEW_STRC, NULL, FALSE, MFT_RADIOCHECK);
//Подключаем временные меню к главному меню
i=0; //Инициализация позиции в меню hMainMenu
CreateMenuItem( hMainMenu, TEXT("&Файл"), i++, 0, hFileMenu, FALSE, MFT_STRING);
SetMenu(hwnd, hMainMenu);
SetMenuItem(hFileMenu, CM_FILE_SAVE, MFS_GRAYED, FALSE);
DrawMenuBar(hwnd);
return 0;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case CM_FILE_OPEN:
{
SetMenuItem( hFileMenu, CM_FILE_OPEN, MFS_GRAYED, FALSE);
SetMenuItem( hFileMenu, CM_FILE_SAVE, MFS_ENABLED, FALSE);
CreateMenuItem( hMainMenu, TEXT("&Правка"), 1, 0, hEditMenu, FALSE, MFT_STRING);
CreateMenuItem( hMainMenu, TEXT("&Вид"), 2, 0, hViewMenu, FALSE, MFT_STRING);
DrawMenuBar(hwnd);
return 0;
}
case CM_FILE_SAVE:
{
SetMenuItem( hFileMenu, CM_FILE_SAVE, MFS_GRAYED, FALSE);
SetMenuItem( hFileMenu, CM_FILE_OPEN, MFS_ENABLED, FALSE);
RemoveMenu(hMainMenu, 1, MF_BYPOSITION);
RemoveMenu(hMainMenu, 1, MF_BYPOSITION);
DrawMenuBar(hwnd);
return 0;
}
case CM_EDIT_FIND:
{
if (GetMenuItem( hEditMenu, CM_EDIT_FIND, FALSE)==MFS_CHECKED)
SetMenuItem( hEditMenu, CM_EDIT_FIND, MFS_UNCHECKED, FALSE);
else SetMenuItem( hEditMenu, CM_EDIT_FIND, MFS_CHECKED, FALSE);
return 0;
}
case CM_EDIT_REPLC:
{
if (GetMenuItem( hEditMenu, CM_EDIT_REPLC, FALSE)==MFS_CHECKED)
SetMenuItem( hEditMenu, CM_EDIT_REPLC, MFS_UNCHECKED, FALSE);
else SetMenuItem(hEditMenu, CM_EDIT_REPLC, MFS_CHECKED, FALSE);
return 0;
}
case CM_VIEW_NORM:
{
SetMenuItem( hViewMenu, CM_VIEW_NORM, MFS_CHECKED, FALSE);
SetMenuItem( hViewMenu, CM_VIEW_STRC, MFS_UNCHECKED, FALSE);
return 0;
}
case CM_VIEW_STRC:
{
SetMenuItem( hViewMenu, CM_VIEW_NORM, MFS_UNCHECKED, FALSE);
SetMenuItem( hViewMenu, CM_VIEW_STRC, MFS_CHECKED, FALSE);
return 0;
}
case CM_FILE_QUIT: { DestroyWindow(hwnd); return 0; }
}
return 0;
}
case WM_DESTROY:
{ DestroyMenu(hEditMenu); DestroyMenu(hViewMenu); PostQuitMessage(0); return 0; }
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Это приложение от предыдущего отличается следующим:
1. Временные меню hEditMenu и hViewMenu в главное меню вставляют после выбора строки "Открыть". Отсутствует проверка состояния fFileOpened. Взамен введено управление состоянием элементов меню. Например, пока файл не открыт, заблокирован элемент "Сохранить":
SetMenuItem(hFileMenu, CM_FILE_SAVE, MFS_GRAYED, FALSE);
А после открытия файла этот элемент разблокируется:
SetMenuItem(hFileMenu, CM_FILE_SAVE, MFS_ENABLED, FALSE);
и блокируется элемент "Открыть":
SetMenuItem( hFileMenu, CM_FILE_OPEN, MFS_GRAYED, FALSE);
Блокировка элемента гарантирует, что его строку нельзя выбрать.
2. Временные меню hEditMenu и hViewMenu удаляют из главного меню после выбора строки "Сохранить".
3. В разделе "Правка" строки "Найти" и "Заменить" могут быть отмечены галочкой. Обратите внимание, что при вставке этих элементов ничего не изменилось. Для отметки галочкой достаточно установить состояние MFS_CHECKED. Например:
SetMenuItem(hEditMenu, CM_EDIT_FIND, MFS_CHECKED, FALSE);
В приложении эта часть задачи решается более широко. Например, проверяется текущее состояние элемента. Если элемент перед выбором был уже отмечен галочкой, то снимается отметка, и если он перед выбором не был отмечен, то отмечается галочкой:
if(GetMenuItem(hEditMenu, CM_EDIT_FIND, FALSE)==MFS_CHECKED)
SetMenuItem(hEditMenu, CM_EDIT_FIND, MFS_UNCHECKED, FALSE);
else
SetMenuItem(hEditMenu, CM_EDIT_FIND, MFS_CHECKED, FALSE);
Элементы временного меню hViewMenu используются как зависимые переключатели. Поэтому задан тип MFT_RADIOCHECK:
CreateMenuItem(hViewMenu, "&Обычный", i++,
CM_VIEW_NORM, NULL, FALSE, WFT_RADIOCHECK);
Это гарантирует, что метка элемента будет отображаться черным кружочком (а не галочкой).
При выборе любой строки меню hViewMenu устанавливают этот элемент в отмеченное состояние, а другой элемент этого меню – в неотмеченное. Например, при выборе элемента CM_VIEW_NORM устанавливают этот элемент в отмеченное состояние:
SetMenuItem(hViewMenu, CM_VIEW_NORM, MFS_CHECKED, FALSE);
а элемент СМ_VIEW_STRC устанавливают в неотмеченное состояние:
SetMenuItem(hViewMenu, CM_VIEW_STRC, MFS_UNCHECKED, FALSE);