EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Откомпилируйте файл и выполните проект.
Просмотрите и проанализируйте, как работают пункты меню всех уровней, какие параметры функции drawShape изменяются в при поступлении сообщения от конкретного пункта меню и как это изменение влияет на поведение функции.
- Подменю может содержать один пункт, выполняемый по умолчанию. Имя этого пункта выделяется жирным шрифтом. Когда пользователь открывает подменю двойным щелчком, Windows автоматически выполнит команду по умолчанию, закрыв при этом подменю. Если пункт по умолчанию отсутствует, то двойной щелчок приводит просто к открытию подменю.
Атрибут «применяемый по умолчанию» может быть назначен любому пункту подменю при помощи функции:
BOOL SetMenuDefaultItem(HMENU hMenu, // дескриптор подменю UINT uItem, // идентификатор пункта подменю, назначаемого пунктом по умолчанию UINT fByPos // если этот третий параметр назначается FALSE);
Создайте в блоке обработки сообщений функции WndProc обработку сообщения WM_CREATE и выполните в нем функцию, сделав таким образом пунктом по умолчанию пункт «Открыть»:
SetMenuDefaultItem(GetSubMenu(hMenu,0), IDM_OPEN, FALSE);
Обратите внимание, что дескриптор подменю определяется функцией
HMENU GetSubMenu(HMENU hMenu, // дескриптор родительского меню int nPos // позиция-уровень пункта подменю в родительском меню);
Относительная позиция nPos для родительского меню отсчитывается от нуля.
Откомпилируйте файл и выполните проект. Просмотрите и проанализируйте, как работают пункты «Открыть» и любого другого пункта меню нулевого уровня.
- Пункты меню могут использоваться в роли переключателей (radio button). Переключатели обычно используются в группе. В группе можно выбрать только один переключатель, поэтому в группу связываются только пункты подменю с взаимно исключающими опциями. Выбранный переключатель отмечается жирной точкой.
HMENU hmenu, // дескриптор меню UINT idFirst, // идентификатор или позиция первого пункта меню в группе UINT idLast, // идентификатор или позиция последнего пункта меню в группе UINT idCheck, // идентификатор или позиция выбранного пункта меню из группы UINT uFlags // интерпретация параметра idFirst, idLast или idCheck);
Если параметр uFlags имеет значение MF_BYCOMMAND, то параметры со второго по четвертый указывают идентификаторы пунктов меню. Если параметр uFlags равен MF_BYPOSITTION, то эти параметры указывают позиции пунктов меню.
Задавая в редакторе пункты меню для группы переключателей, следует убедиться, что их идентификаторы в файле Resurce.h имеют сквозную нумерацию и упорядочены в соответствии с позициями этих пунктов на полосе меню. При нарушении этого условия функция CheckMenuRadioItem может работать некорректно.
Создайте группу из двух пунктов подменю «Видимость» - «Скрыть» и «Показать». Для этого инициализируйте группу и начальное положение в группе пункта «Скрыть», вызвав функцию с параметрами
CheckMenuRadioItem(GetSubMenu(hMenu,1),IDM_SHOW_SHAPE,
IDM_HIDE_SHAPE, IDM_SHOW_SHAPE, MF_BYCOMMAND);
в блоке блоке сообщения WM_CREATE.
В блоке сообщений WM_COMMAND при обработке его младшего слова wParam со значениями, равными всем идентификаторам пунктов меню создаваемой группы вызвать функцию
case IDM_SHOW_SHAPE:
CheckMenuRadioItem(GetSubMenu(hMenu,1),IDM_ SHOW_SHAPE,
IDM_ HIDE_SHAPE, LOWORD(wParam), MF_BYCOMMAND);
case IDM_HIDE_SHAPE:
CheckMenuRadioItem(GetSubMenu(hMenu,1),IDM_ SHOW_SHAPE,
IDM_ HIDE_SHAPE, LOWORD(wParam), MF_BYCOMMAND);
Откомпилируйте файл и выполните проект. Просмотрите и проанализируйте, как работают пункты созданной группы пунктов меню.
Аналогично создайте группы пунктов:
Группа | Позиция nPos в функции GetSubMenu | Первый пункт в группе | Последний пункт в группе |
подменю «Фигура» | ID_RECTANGLE | ID_ELLIPSE | |
подменю «Цвет» | ID_RED | ID_BLUE | |
ID_DARK | ID_LIGHT |
Откомпилируйте файл и выполните проект. Проверьте, как работают пункты созданных групп пунктов меню.
8. Пункт главного меню «Увеличить!» с идентификатором IDM_RESIZE является командой и должен использоваться как флажок, сигнализирующий об изменении размеров фигуры. Вставьте в блок «case IDM_RESIZE:» инструкцию, изменяющую значение shapeSize:
shapeSize = (shapeSize == MIN)? MAX: MIN;
// значение, которое будет принимать объект shapeSize 0 или 1
Пункты меню нулевого уровня не могут получать отметку взведенного флажка. Показать пользователю реакцию на его действие следует, изменив заголовок пункта-команды функцией ModifyMenu.
BOOL ModifyMenu(HMENU hMnu, // дескриптор меню UINT uPosition, // идентификатор или позиция пунктаUINT uFlags, // флаги (значение MF_BYCOMMAND или // MF_BYPOSITTION) PTR uIDNewItem, // новый идентификатор пункта LPCTSTR lpNewItem // новое название пункта);
Перед оператором switch в функции WndProc создайте массив из двух строк типа TCHAR и инициализируйте его названиями пунктов меню:
TCHAR* itemResizeName[2] = {TEXT("Увеличить!"),TEXT("Уменьшить!")};
И добавьте следующие инструкции в блок «case IDM_RESIZE:»
ModifyMenu(hMenu, IDM_RESIZE, MF_BYCOMMAND, IDM_RESIZE,
itemResizeName[shapeSize]); // индекс 0 или 1!!
DrawMenuBar(hWnd); // перерисовать меню с новым названием
// пункта
Откомпилируйте файл и выполните проект.
Проверьте, как работает пункт «Увеличить!» главного меню.
9. Когда изображение скрыто после выполнения команды «Скрыть» подменю «Видимость», действия по рисованию фигуры, изменению ее размеров, цветов и их оттенков теряют смысл. Интерфейс программы выиграет, если в этой ситуации соответствующие пункты меню сделать недоступными. Этого можно достичь, используя функцию EnableMenuItem.
BOOL EnableMenuItem(HMENU hMenu, // дескриптор меню UINT uIDEnableItem, // идентификатор или позиция пункта UINT uEnable // интерпретация второго параметра и выполняемое действие);
Три действия может определять параметр uEnable:
· MFS_ENABLED (пункт разрешен),
· MFS_DISABLED (пункт запрещен),
· MFS_GRAYED (пункт недоступен).
Сделайте недоступным пункт меню IDM_RESIZE. При обработке сообщения WM_COMMAND, с параметром wParam, равным IDM_HIDE_SHAPE, вызовите функцию EnableMenuItem, которой передается флаг MF_BYCOMMAND|MFS_GRAYED.
EnableMenuItem (hMenu, IDM_RESIZE, MF_BYCOMMAND|MFS_GRAYED);
DrawMenuBar(hWnd); // не забудьте перерисовать меню!!!!!!!!
А при обработке сообщения WM_COMMAND, с параметром wParam, равным IDM_SHOW_SHAPE, вызовите туже функцию EnableMenuItem, но с флагом MF_BYCOMMAND|MFS_ENABLED.
EnableMenuItem (hMenu, IDM_RESIZE, MF_BYCOMMAND|MFS_ ENABLED);
DrawMenuBar(hWnd); // не забудьте перерисовать меню!!!!!!!!
Откомпилируйте файл и выполните проект. Проверьте, как работает пункт «Увеличить!» главного меню при отжатом пункте меню «Скрыть».
Для того чтобы сделать недоступным много пунктов меню, нужно применить эти функции многократно для всех пунктов. Как уже говорилось, при отжатом пункте меню «Скрыть» бессмысленно выполнение пунктов меню с идентификаторами ID_RECTANGLE, ID_RHOMB, ID_ ELLIPSE, ID_ RED, ID_ GREEN, ID_BLUE, ID_DARK, ID_LIGHT, ID_MEDIUM. Помня, что идентификатор пункта меню – это объект типа определите открытый массив
UINT IdPunktMenu [ ] = { IDM_RESIZE,
ID_RECTANGLE, ID_RHOMB, ID_ELLIPSE,
ID_RED, ID_GREEN, ID_BLUE,
ID_DARK, ID_LIGHT, ID_MEDIUM };
Размер этого массива можно вычислить как sizeof (IdPunktMenu) / sizeof(UINT).
Разработайте свою функцию с тем же именем EnableMenuItem, которая, получает адрес массива идентификаторов IdPunktMenu, количество его элементов n, а также параметр UINT uEnable и вызывает стандартную функцию EnableMenuItem столько раз, сколько идентификаторов пунктов меню в массиве, т.е.создайте функцию с заголовком:
void EnableMenuItem (HMENU hMenu, UINT* IdPunktMenu, int n, UINT uEnable).
Замените в функции в соответствующих ветвях case стандартную функцию EnableMenuItem на разработанную вами функцию.
Откомпилируйте файл и выполните проект. Проверьте, как работают пункты меню при «отжатом» пункте меню «Скрыть».
10. Быстрая клавиша (keyboard accelerator) – это клавиша или комбинация клавиш, которые при нажатии генерируют сообщение WM_COMMAND. Обычно быстрые клавиши дублируют пункты меню, предоставляя пользователю альтернативный способ вызова команд.
Чтобы добавить в приложение обработку быстрых клавиш, нужно выполнить простую последовательность действий:
- Модифицировать определение ресурса меню, добавив к имени каждого дублируемого пункта информацию о быстрой клавише.
- Определить быструю клавишу в таблице быстрых клавиш файла описания ресурсов
В главной функции _tWinMain обеспечивается загрузка таблицы быстрых клавиш функцией LoadAccelerators, а функция TranslateAccelerator перехватывает сообщения с клавиатуры, анализирует их коды и в случае совпадения с кодом, определенным в таблице быстрых клавиш, направляет соответствующее сообщение в оконную процедуру главного окна. Еще раз посмотрите на цикл обработки сообщений в функции _tWinMain!
Добавьте горячую клавишу для пункта меню «Открыть» - alt + Т (Т символ кириллицы).
В окне Обозреватель решений откройте файл ваша_ фамилия.rc двойным щелчком. В появившемся окне Окно ресурсов откройте папку Menu, щелкнув по его пункту IDC_MY (это идентификатор главного меню), и откройте Редактор меню.
Сделайте подсказку пользователю о наличии горячей клавише. Вызовите диалоговое окно Свойства для пункта меню «Открыть» и в конце имени пункта, которое указано в поле Надпись, добавьте текстовую строку, подсказывающую пользователю, какая горячая клавиша или сочетание клавиш являются горячими для этого пункта меню. В данном случае добавьте к имени “…\alt + Т ”
В окне Окно ресурсов откройте папку Accelerator и, щелкнув по ее пункту, откройте редактор таблицы быстрых клавиш. В поле ID таблицы выберите идентификатор пункта «Открыть», в поле Модификатор (Modifier) виртуальное имя клавиши alt, в поле Ключ (Key) пропишите символ Т, поле Тип (Type) оставьте ASCII.
Откомпилируйте файл и выполните проект. Проверьте, как работают горячие клавиши.
Добавьте несколько горячих клавиш по своему усмотрению.
Теоретически, можно определить быструю клавишу почти для каждой виртуальной или символьной клавиши в сочетании с клавишами Shift, Ctrl или Alt. Однако надо избегать тех быстрых клавиш, которые имеют традиционное применение во многих приложениях Windows.
При защите общей части этой лабораторной работы вы должны продемонстрировать преподавателю практические навыки работы в графическом редакторе, умение читать и понимать созданное вами приложение и уметь отвечать на теоретические вопросы, список которых приводится ниже.
1. Что такое сообщение?
2. Как реализовано сообщение?
3. Windows многозадачная система. Кому адресуются сообщения?
4. Что такое системная очередь сообщений? Кто ее создает? Когда?
5. Как Windows определяет адресата, которому предназначено сообщение?
6. Что такое дескриптор?
7. Что такое очередь сообщений приложения? Кто ее создает? Когда? Зачем? Как долго живет эта очередь?
8. Что такое оконная процедура?
9. Какая функция называется функцией обратного вызова?
10. Как компилятор узнает функцию обратного вызова?
11. Какой заголовок у функции обратного вызова главного окна?
12. Какие параметры имеет оконная процедура?
13. Какова структура тела функции обратного вызова?
14. Что такое оконный класс?
15. Что определяет оконный класс?
16. Какую возможность дает использование одного и того же класса при создании множества окон?
17. Какова структура главной функции WinMain?
18. Что такое hInstance?
19. Что происходит в цикле обработки сообщений?
20. Зачем приложению извлекать сообщения из очереди сообщений, а затем снова возвращать их Windows?
21. Когда посылается сообщение WM_COMMAND?
22. Что делает макрос LOWORD?
23. Что делает макрос HIWORD?
24. Какую информацию содержит младшее слово параметра wParam, когда обрабатывается сообщение WM_COMMAND?
25. Какую информацию содержит младшее слово параметра wParam, когда обрабатывается сообщение WM_COMMAND?
26. Что такое контекст устройства?
26. Перечислите основные графические объекты.
27. Какие действия необходимо выполнить при использовании графических объектов?
28. О чем уведомляет приложение сообщение WM_PAINT?
29.Когда посылается сообщение WM_PAINT?
30. В каких ситуациях клиентская область окна становится недействительной?
31. Назовите функцию, которая посылает сообщение WM_PAINT и перерисовывает клиентскую/ область окна с дескриптором hWnd?
32. Какие различают типы пунктов меню?
33. Что такое пункт-команда?
34. Какие действия следуют за выбором пункта-команды меню?
35. Что такое пункт-подменю?
36. Какие действия следуют за выбором пункта-подменю?
37. Какими могут быть пункты меню по уровню доступности?
38. Какой уровень доступности пунктов меню назначается по умолчанию?
39. Что нужно сделать, чтобы пользователь знал, что пункт «отменен»?
40. Какая функция изменяет уровень доступности пунктов меню?
41. С помощью какой функции можно получить дескриптор подменю?
42. Какой функцией можно задать группы переключателей?
ЛАБОРАТОРНАЯ РАБОТА №2
Цель работы: Освоение приемов создания диалоговых окон. Работа в редакторе ресурсов.
Лабораторная работа имеет как общее задание, так и индивидуальные задания.
Теоретический материал
Диалоговые окна, или окна диалога (dialog box), реализуют для организации интерфейса с пользователем – получение дополнительной информации и вывода результатов работы приложения.
Диалоговое окно имеет вид всплывающего окна с одним или несколькими элементами управления (controls), которые являются дочерними окнами по отношению к диалоговому окну. Сообщения для диалогового окна поступают через функцию диалогового окна (dialog procedure), которая является функцией обратного вызова и очень похожа на обычную оконную процедуру, хотя и имеет некоторые важные отличия.
Диалоговые окна всегда связаны с шаблоном диалога, содержащим размеры окна, состав и расположение его элементов управления. Шаблон диалогового окна создают, используя редактор диалоговых окон.
Диалоговые окна бывают модальными (modal) и немодальными (modeless).
Модальное диалоговое окно ожидает выполнения некоторого действия со стороны пользователя, прежде чем приложение сможет продолжить свое выполнение. Пользователь не может переключиться между диалоговым окном и другими окнами приложения. Он должен явно закрыть модальное диалоговое окно кнопками OK или Cancel. Однако пользователь может переключаться на другие приложения.
Немодальное диалоговое окно не приостанавливает выполнение программы. Оно может свободно получать и терять фокус ввода. Это значит, что пользователь свободно может переключаться между диалоговым окном и другими окнами приложения.
Основную функциональную нагрузку в диалоговом окне выполняют элементы управления. Все версии Windows поддерживают базовые элементы управления, перечисленные в таблице.
Элемент управления | Описание |
Рисунок (Picture control) | Элемент управления, отображающий пустую прямоугольную рамку, закрашенную прямоугольную область или растровый образ |
Надпись (Static text) | Текстовая строка. Обычно используется как метка (поясняющая надпись) рядом с полем ввода или элементом управления другого типа. Может применяться как самостоятельная информационная надпись. |
Рамка (Group box) | Прямоугольная рамка с надписью, используемая для группирования набора связанных элементов управления. |
Кнопка (Button) | Элемент, который пользователь «нажимает», чтобы выполнить какое-либо действие |
Флажок (Check box) | Элемент, который может быть либо установлен, либо сброшен для выбора или отмены опции, которая не связана с другими опциями. |
Переключатель (Radio button) | Элемент, используемый для выбора одной из группы взаимоисключающих опций. В группе переключателей может быть выбран только один из них. |
Список (List control) | Прямоугольное окно со списком элементов (строк), из которого пользователь может выбрать любой элемент. |
Окно редактирования или текстовое поле (Edit control) | Прямоугольное окно для ввода текста с клавиатуры. Элемент предоставляет определенные средства редактирования текста. |
Комбинированный список (Combo box) | Элемент, объединяющий список с окном редактирования |
Полоса прокрутки (Scroll bar) | Элемент управления линейкой прокрутки. |
Если элемент управления создан, то программисту известен только его идентификатор. В тоже время функции, работающие с элементом управления, принимают в качестве параметра его дескриптор. Для получения дескриптора используется функция:
HWND GetDlgItem(HWND hDlg, // дескриптор диалогового окна int nIDDlgItem // идентификатор элемента управления);
В случае успешного завершения функция возвращает дескриптор элемента управления, в случае возникновения ошибки - 0.
Элементы управления могут быть разрешенными (enabled) или запрещенными (disabled).
По умолчанию все элементы управления имеют статус разрешенных.