Удаление элементов из меню

УП. 4. Создание меню

План:

УП. 4. Создание меню.. 1

4.1. Элементы меню.. 2

4.2. Создание меню.. 4

4.2.1. Вставка элементов в меню.. 6

4.2.2. Удаление элементов из меню.. 11

4.2.3. Управление состоянием элементов меню.. 15

4.2.4. Получение информации о меню.. 22

4.3. Сообщения от меню.. 26

4.3.1. Сообщение WM_INITMENU.. 26

4.3.2. Сообщение WM_INITMENUPOPUP. 27

4.3.3. Сообщение WM_COMMAND.. 27

4.3.4. Сообщение WM_MENUSELECT. 27

4.4. Плавающее меню.. 27

4.5. Акселераторы.. 31

Контрольные вопросы.. 45

Упражнения. 45

Меню используют для выбора команд и изменения режимов работы приложения. Строки меню отражают название раздела меню или смысл связанной со строкой команды. Если строка связана с командой, при ее выборе приложение получает сообщение WM_COMMAND и идентификатор этой команды.

Основным отображаемым элементом меню является строка или графический объект. Здесь рассматриваются только строки. Они в текстовом виде отображают названия разделов или команд меню, а также клавиш быстрого доступа. Строка может быть отмечена галочкой или иным образом. Такая строка используется как флажок или переключатель, изменяющий режим работы приложения. Если при выборе строки на экране должна появиться диалоговая панель, к слову справа добавляют многоточие. Заблокированные строки меню отображают серым цветом.

Любое перекрывающееся или временное окно может иметь меню. Главное меню находится ниже заголовка окна, и его строки расположены в одну или несколько линий. При выборе строки главного меню, как правило, активизируется раздел меню. Раздел меню представляет собой временное меню.

Строки временного меню расположены в один или несколько столбцов. Если временное меню может появляться в любом месте рабочей области, то оно называется плавающим. В некоторых случаях удобнее применять плавающее меню. Они "всплывают" после щелчка обычно правой клавиши мыши, и место "всплытия" нетрудно связать с координатами курсора мыши. Тогда легче выбрать нужную строку меню. Кроме того, по координатам курсора мыши можно определить объект, по изображению которого был сделан щелчок, и задать зависимый от этого объекта набор строк меню.

Если окно имеет системное меню, то оно расположено слева от текста заголовка окна.

По способу создания различают статическое и динамическое меню. Статическое меню создают до запуска и не изменяют в процессе работы приложения. Динамическое меню создают в процессе работы приложения. Динамическое меню после создания можно изменять или оставить неизменным. Работа со строками статических и динамических меню ничем не отличается. Здесь рассматриваются способы создания только динамических меню.

Элементы меню

Пользователь видит и работает со строками меню, а приложение работает с элементами меню. Любой элемент меню может быть описан с помощью структуры MENUITEMINFO:

typedef struct

{

UINT cbSize;

UINT fMask;

UINT fType;

UINT fState;

UINT wID;

HMENU hSubMenu;

HBITMAP hbmpChecked;

HBITMAP hbmpUnchecked;

DWORD dwItemData;

LPTSTR dwTypeData;

UINT cch;

} MENUITEMINFO;

Рассмотрим пример работы с переменной этого типа:

static MENUITEMINFO mii;

В поле cbsize записывают размер структуры MENUITEMINFO в байтах:

mii.cbSize = sizeof(MENUITEMINFO);

Значение поля fMask указывает операционной системе, со значениями каких полей структуры mii нужно работать. Смысл работы зависит от действия, которое выполняют над элементом меню. Значение поля fMask представляет собой комбинацию констант из следующей таблицы:

Константа Co значениями каких полей работать
MIIM_CHECKMARKS hbmpChecked и hbmpUnchecked
MIIM_DATA dwItemData
MIIM_ID wID
MIIM_STATE fState
MIIM_SUBMENU hsubMenu
MIIM_TYPE fType и dwTypeData

Например, при создании элемента меню значение поля fMask задают следующим образом:

mii.fMask = MIIM_STATE | MIIM_TYPE | MIIM_SUBMENU | MIIM_ID;

Тогда операционная система при создании элемента будет учитывать значения полей fState, fType, dwTypeData, hSubMenu и wID структуры mii.

Для установки состояния элемента меню значение поля fMask комбинируют по-другому:

mii.fMask = MIIM_STATE | MIIM_ID;

Тогда операционная система будет учитывать значения полей fState и wID.

Поле fType задает тип элемента. В следующей таблице перечислены некоторые допустимые значения:

Константа Пояснение
MFT_BITMAP Элемент меню отображать графическим объектом, дескриптор которого находится в младшем слове поля dwTypeData, а поле cch игнорировать
MFT_MENUBARBREAK Элемент меню отображать в начале новой строки (при построчном отображении элементов) или нового столбца (при отображении элементов по столбцам). Между столбцами появится вертикальная линия
MFT_MENUBREAK То же, что и MFT_MENUBARBREAK, но между столбцами нет вертикальной линии
MFT_RADIOCHECK Если hbmpChecked = NULL, то элемент помечать кружочком, а не галочкой
MFT_RIGHTJUSTIFY Выравнивать этот и последующие элементы меню по правому краю
MFT_SEPARATOR В качестве элемента отобразить разделитель в виде горизонтальной линии. Поля dwTypeData и cch игнорировать
MFT_STRING Элемент меню отображать строкой из поля dwTypeData, cch равно длине этой строки

Константы этой таблицы могут комбинироваться, но несовместимы MFT_BITMAP, MFT_SЕРARATOR и MFT_STRING.

Пример. Для создания элемента меню, отображаемого в виде строки, записывают:

mii.fType=MFT_STRING;

Поле fState задает состояние элемента меню. Оно принимает следующие значения:

Значение Состояние элемента меню
MFS_CHECKED Отмечен
MFS_DEFAULT Элемент по умолчанию
MFS_DISABLED Заблокирован
MFS_ENABLED В активном состоянии
MFS_GRAYED Заблокирован
MFS_HILITE Подсвечен
MFS_UNCHECKED Не отмечен
MFS_UNHILITE Не подсвечен

Поле wID содержит определяемый приложением идентификатор команды, связанный с элементом меню.

Пример. Пусть создается элемент меню, который отображается строкой "Создать" и связан с идентификатором CM_FILE_NEW.

Идентификатор создают обычным способом:

#define CM_FILE_NEW 3001

Тогда этот идентификатор в поле wID можно записать так:

mii.wID = CM_FILE_NEW;

Поле hSubMenu содержит дескриптор временного меню, которое должно появиться при выборе этого элемента. Если меню не должно появиться, это поле содержит NULL.

Поле hbmpChecked содержит дескриптор изображения метки для отмеченного элемента. Если это поле содержит NULL, используется символ переключателя или галочка.

Поле hbmpUnchecked содержит дескриптор изображения метки для неотмеченного элемента. Если это поле содержит NULL, данное состояние ничем не отображается.

Поле dwItemData – определяемое приложением значение, связанное с элементом меню.

Поле dwTypeData – содержание отображения элемента. В случае mii.fType = MFT_STRING в поле dwTypeData записывают строку.

Поле cch равно длине строки dwTypeData или 0.

Создание меню

Алгоритм создания меню в общем случае содержит следующие шаги:

1. Создание пустого меню hMenu.

2. Вставка элемента в меню hMenu.

3. Шаг 2 повторяем столько раз, сколько элементов содержит меню hMenu.

Этот алгоритм позволяет создавать многоуровневое меню. Например, вставляемый на 2-м шаге элемент может указывать на уже созданное временное меню. Причем любой элемент последнего также может указывать на временное меню.

Меню сначала создают только в памяти. Существуют функции, которые операционной системе указывают, какое меню создано, какому окну оно принадлежит и когда его отображать. Рассмотрим эти функции.

Функция CreateMenu создает пустое главное меню окна:

HMENU CreateMenu(VOID);

В случае успешного выполнения функция CreateMenu возвращает дескриптор созданного главного меню, иначе – NULL.

Функция CreatePopupMenu создает пустое временное меню:

HMENU CreatePopupMenu(VOID);

В случае успешного выполнения функция CreatePopupMenu возвращает дескриптор созданного временного меню, иначе – NULL.

Функция SetMenu подключает главное меню hMenu к окну hwnd:

BOOL SetMenu(HWND hwnd, HMENU hMenu );

Она удаляет предыдущее меню, но не разрушает его. Если же hMenu = NULL, то только удаляется главное меню. В случае успешного подключения функция возвращает ненулевое значение.

После изменений в меню, независимо от состояния окна hwnd, для перерисовки полосы меню нужно вызвать функцию DrawMenuBar:

void WINAPI DrawMenuBar(HWND hwnd);

Она перерисовывает полосу меню окна hwnd.

Таким образом, алгоритм подключения главного меню к окну и отображения полосы меню содержит следующие шаги:

1. Создание главного меню. Этот шаг полностью совпадает с алгоритмом создания меню.

2. Подключение главного меню к окну.

3. Перерисовка полосы меню окна.

После этого работу с меню обеспечивает операционная система.

Приложение в созданное меню может вставлять новые элементы или удалять старые, а также может изменять или запрашивать текущее состояние любого элемента.

Вставка элементов в меню

Функция InsertMenuItem вставляет элемент в меню hMenu:

BOOL InsertMenuItem(HMENU hMenu, UINT uItem,

BOOL fByPosition, LPMENUITEMINFO lpmii);

Значение аргумента uItem зависит от значения fByPosition. При fByPosition = FALSE значение uItem равно идентификатору команды вставляемого элемента, иначе – позиции того элемента в меню, перед которым нужно вставить новый элемент. Если меню содержит n элементов и нужно вставить новый элемент последним, то номер позиции приравнивают n (n = 0, 1, 2, ...).

Параметр lpmii указывает на структуру типа MENUITEMINFO, которая уже содержит информацию о вставляемом элементе.

В случае успешной вставки элемента функция возвращает ненулевое значение.

Задача. Описать функцию для вставки элемента в меню.

Нижеследующий фрагмент может служить примером решения данной задачи.

BOOL CreateMenuItem(HMENU hMenu, char *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);

}

Рассмотрим список формальных параметров этой функции.

1. hMenu – дескриптор меню, в который вставляется элемент.

2. str указывает на текст отображения строки меню.

3. uIns равноценен параметру uItem функции InsertMenuItem.

4. uCom, когда он ненулевой, исполняет роль параметра wID функции InsertMenuItem.

5. hSubMenu – дескриптор временного меню, которое должно появиться при выборе строки str в меню hMenu.

6. flag совпадает с параметром fByPosition в InsertMenuItem.

7. fType принимает те же значения, что и поле fType структуры MENUITEMINFO.

Задача. Главное меню содержит разделы "Файлы" и "Правка". При выборе строки "Файлы" отображается временное меню со строками "Открыть", "Сохранить" и "Выход". При выборе строки "Правка" отображается временное меню со строками "Найти" и "Заменить".

Листинг 4.1. Пример приложения со статическим меню.

#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

BOOL RegClass(WNDPROC, LPCTSTR, UINT);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

HINSTANCE hInstance;

TCHAR szClass[] = TEXT("MenuWindow");

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 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;

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);

//Подключаем временные меню к главному меню

i=0; //Инициализация позиции в меню hMainMenu

CreateMenuItem( hMainMenu, TEXT("&Файл"), i++, 0, hFileMenu, FALSE, MFT_STRING);

CreateMenuItem( hMainMenu, TEXT("&Правка"), i++, 0, hEditMenu, FALSE, MFT_STRING);

SetMenu( hwnd, hMainMenu);

DrawMenuBar( hwnd);

return 0;

}

case WM_COMMAND:

{

switch (LOWORD(wParam))

{

case CM_FILE_OPEN:

{ MessageBox(hwnd, TEXT("Команда CM_FILE_OPEN"), TEXT("Меню"), MB_OK); return 0; }

case CM_FILE_SAVE:

{ MessageBox(hwnd, TEXT("Команда CM_FILE_SAVE"), TEXT("Меню"), MB_OK); return 0; }

case CM_EDIT_FIND:

{ MessageBox(hwnd, TEXT("Команда CM_EDIT_FIND"), TEXT("Меню"), MB_OK); return 0; }

case CM_EDIT_REPLC:

{ MessageBox(hwnd, TEXT("Команда CM_EDIT_REPLC"), TEXT("Меню"), MB_OK); return 0; }

case CM_FILE_QUIT: { DestroyWindow(hwnd); return 0; }

}

return 0;

}

case WM_DESTROY: { PostQuitMessage(0); return 0; }

}

return DefWindowProc(hwnd, msg, wParam, lParam);

}

Это приложение демонстрирует применение рассмотренной выше функции CreateMenuItem для создания статического меню. Меню названо статическим потому, что в процессе работы приложения оно не изменяется. Рассмотрим основные шаги создания меню.

1. Описывают дескрипторы для создаваемых меню:

static HMENU hMainMenu, hFileMenu, hEditMenu;

2. При обработке сообщения WM_CREATE создают всю систему меню (хотя не запрещается это делать и в любом другом месте).

2.1. Создают пустое главное меню окна:

hMainMenu = CreateMenu();

2.2. Создают временное меню для раздела "Файлы".

2.2.1. Создают пустое временное меню:

hFileMenu = CreatePopupMenu();

2.2.2. Вставляют элементы в меню hFileMenu:

CreateMenuItem( hFileMenu, "&Открыть", i++, CM_FILE_OPEN,

NULL, FALSE, MFT_STRING);

CreateMenuItem( hFileMenu,"&Сохранить", i++, CM_FILE_SAVE,

NULL, FALSE, MFT_STRING);

CreateMenuItem( hFileMenu, NULL, i++, 0,

NULL, FALSE, MFT_SEPARATOR);

CreateMenuItem( hFileMenu, "&Выход", i++, CM_FILE_QUIT,

NULL, FALSE, MFT_STRING);

Здесь аргумент "&Открыть" обозначает ту строку, которая будет отображена во временном меню. Ключ & обозначает, что символ "О" можно использовать для быстрого доступа к данной строке меню. Аргумент CM_FILE_OPEN является идентификатором той команды, которую получит функция окна при выборе строки "&Открыть".

Так же вставляют второй и четвертый элементы меню. Третьим элементом является разделительная линия.

2.3. Создают временное меню для раздела "Правка".

2.3.1. Создают пустое временное меню:

hEditMenu = CreatePopupMenu();

2.3.2. Вставляют элементы в меню hEditMenu:

CreateMenuItem( hEditMenu, "&Найти", i++, CM_EDIT_FIND,

NULL, FALSE, MFT_STRING);

CreateMenuItem( hEditMenu,"&3aMeHHTb", i++, CM_EDIT_REPLC,

NULL, FALSE, MFT_STRING );

2.4. Подключают временные меню hFileMenu и hEditMenu к главному меню hMainMenu:

CreateMenuItem( hMainMenu, "&Файл", i++,

0, hFileMenu, FALSE, MFT_STRING);

CreateMenuItem( hMainMenu, "&Правка", i++,

0, hEditMenu, FALSE, MFT_STRING);

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

SetMenu(hwnd, hMainMenu);

DrawMenuBar(hwnd);

Приложение обрабатывает команды меню. Как можно увидеть из листинга, обработка команд от меню ничем не отличается от обработки команд от других органов.

Удаление элементов из меню

Функция DeleteMenu удаляет элемент из меню и освобождает все связанные с ним ресурсы. Если удаляемый элемент указывает на временное меню, то функция DeleteMenu удаляет и это временное меню. Прототип функции:

BOOL DeleteMenu( HMENU hMenu, UINT uPosition, UINT uFlags);

Параметры:

1. hMenu – дескриптор изменяемого меню.

2. uPosition определяет удаляемый элемент. Его значение связано со значением параметра uFlags.

3. uFlags задает способ истолкования параметра uPosition. Если uFlags = MF_BYCOMMAND (значение по умолчанию), то значение uPosition равно идентификатору команды удаляемого элемента. Если же uFlags = MF_BYPOSITION, то значение uPosition равно позиции удаляемого элемента в меню.

В случае успешного удаления функция возвращает ненулевое значение.

Функция RemoveMenu удаляет элемент из меню, не разрушая связанные с ним ресурсы. Эти ресурсы можно использовать в дальнейшем. Прототип функции:

BOOL RemoveMenu( HMENU hMenu, UINT uPosition, UINT uFlags);

Параметры функции RemoveMenu подобны параметрам функции DeleteMenu. В случае успешного удаления элемента RemoveMenu возвращает ненулевое значение.

Для разрушения меню вызывают функцию DestroyMenu:

BOOL DestroyMenu( HMENU hMenu);

Эта функция разрушает заданное меню и освобождает ресурсы, которые меню занимает. Эту функцию окна вызывают для разрушения тех меню, которые они создали, но не подключили к себе. Подключенные меню автоматически разрушаются при разрушении окна.

В случае успешного разрушения функция возвращает ненулевое значение.

Задача. Главное меню изначально содержит раздел "Файлы". При выборе строки "Файлы" отображается временное меню со строками "Открыть", "Сохранить", разделительной линией и строкой "Выход". При выборе строки "Открыть" в главное меню добавить элемент "Правка". .При выборе строки "Правка" отображается временное меню со строками "Найти" и "Заменить". Если же затем выбрать строку "Сохранить", то из главного меню удалить элемент "Правка".

Листинг 4.2. Пример удаления элементов меню.

#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

BOOL RegClass(WNDPROC, LPCTSTR, UINT);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

HINSTANCE hInstance;

TCHAR szClass[] = TEXT("RemoveMenu");

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 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;

static BOOL fFileOpened;

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);

//Подключаем временные меню к главному меню

i=0; //Инициализация позиции в меню hMainMenu

CreateMenuItem( hMainMenu, TEXT("&Файл"), i++, 0, hFileMenu, FALSE, MFT_STRING);

SetMenu(hwnd, hMainMenu);

DrawMenuBar(hwnd);

fFileOpened = FALSE;

return 0;

}

case WM_COMMAND:

{

switch (LOWORD(wParam))

{

case CM_FILE_OPEN:

{

if (!fFileOpened)

{

CreateMenuItem( hMainMenu, TEXT("&Правка"), 1, 0, hEditMenu, FALSE, MFT_STRING);

DrawMenuBar( hwnd );

fFileOpened = TRUE;

}

return 0;

}

case CM_FILE_SAVE:

{

if (fFileOpened)

{

RemoveMenu(hMainMenu, 1, MF_BYPOSITION);

DrawMenuBar( hwnd);

fFileOpened = FALSE;

}

return 0;

}

case CM_EDIT_FIND:

{

MessageBox(hwnd, TEXT("Команда CM_EDIT_FlND"), TEXT("Меню"), MB_OK);

return 0;

}

case CM_EDIT_REPLC:

{

MessageBox(hwnd, TEXT("Команда CM_EDIT_REPLC"), TEXT("Меню"), MB_OK);

return 0;

}

case CM_FILE_QUIT: { DestroyWindow(hwnd); return 0; }

}

return 0;

}

case WM_DESTROY:

{

if (!fFileOpened) DestroyMenu( hEditMenu);

PostQuitMessage(0);

return 0;

}

}

return DefWindowProc(hwnd, msg, wParam, lParam);

}

Это приложение от предыдущего отличается следующим:

1. Временное меню hEditMenu в главное меню вставляют лишь после выбора строки "Открыть". При этом проверяют флаг состояния fFileOpened – если файл открыт, то меню hEditMenu уже вставлено в главное меню и еще раз его вставлять не нужно:

if (!fFileOpened)

{

CreateMenuItem( hMainMenu, "&Правка", 1, 0, hEditMenu,

FALSE, MFT_STRING);

DrawMenuBar( hwnd);

fFileOpened=TRUE;

}

Как видим, операция вставки буквально скопирована из предыдущего приложения.

2. Временное меню hEditMenu удаляют из главного меню после выбора строки "Сохранить". Здесь закрытие файла подразумевается. При этом проверяют флаг состояния fFileOpened – если файл закрыт, то меню hEditMenu уже удалено и еще раз его удалять не нужно:

if (fFileOpened)

{

RemoveMenu( hMainMenu, 1, MF_BYPOSITION );

DrawMenuBar( hwnd);

fFileOpened=FALSE;

}

3. До разрушения окна проверяют, вставлено ли меню hEditMenu в главное меню. Если нет, то его нужно разрушать отдельно:

if (!fFileOpened) DestroyMenu( hEditMenu);

Наши рекомендации