- Двойным щелчком мыши на прямоугольнике вызовите окно Properties.
- Проверьте, установлен ли флажок Всплывающее меню (Pop-up).
- При необходимости установите другие опции пункта.
- И только после этого в прямоугольник пункта или поле атрибута Надпись введите имя пункта меню-команды, если оно содержит мнемонический символ, то перед таким символом нужно вставить символ &.
Процедура определения пункта-команды
- Двойным щелчком мыши на прямоугольнике вызовите окно Properties.
- Проверьте, установлен ли флажок Всплывающее меню (Pop-up), если он установлен, сбросьте его.
- Введите идентификатор пункта в поле атрибута ID
- При необходимости установите другие опции пункта.
- И только после этого в прямоугольник пункта или поле атрибута Надпись введите имя пункта меню-команды, если оно содержит мнемонический символ, то перед таким символом нужно вставить символ &.
Процедура определения горизонтальной разделительной линии
- В прямоугольник введите произвольное имя.
- Двойным щелчком мыши на прямоугольнике вызовите окно Properties.
- Сбросьте флажок Pop-up.
- Установите флажок Разделитель (Separator)
Если возникает необходимость перегруппировать пункты меню в пределах конкретного уровня, то можно перетащить пункты в нужную позицию при помощи мыши.
Задание на лабораторную работу
В лабораторной работе необходимо создать приложение, которое должно рисовать одну из трех фигур по выбору пользователя:
- прямоугольник,
- ромб,
- эллипс.
Фигуры должны быть закрашены однородной кистью одним из трех цветов (красный, зеленый, синий). Цвет заливки фигуры выбирает пользователем в соответствующем пункте подменю. Пользователь может задать через меню интенсивность цвета, выбираемый из трех вариантов (Dark- темный цвет, Medium - средний по интенсивности цвет, Light - светлый цвет), размер фигуры также задает пользователь в соответствующих пунктах меню, выбирая размер из двух возможных (фиксированный приложением размер или максимальный размер, определенный размером клиентской области окна). Приложение должно скрывать или показывать изображение фигур по требованию пользователя, выраженное опять же через соответствующие пункты меню.
В приложении должно функционировать подменю File, пункты которого вызывают окна сообщений с информацией о выбранном пункте.
1. Прочитайте текст функции drawShape и разберитесь в том, как и что она делает. Функция реализует возможность управления своей работой, получая от вызывающей ее функции соответствующие управляющие данные через свои параметры.
Вам предстоит сделать меню, которое будет изменять по требованию пользователя ее входные параметры этой функции и таким образом управлять режимом ее работы.
#define W 200 // фиксированная ширина фигуры
#define H 140 // фиксированная высота фигуры
enum ShapeSize {MIN, MAX }; // именованная константа MIN = 0, MAX = 1
struct SHAPE_DATA {
int id_shape; // целое, определяет идентификатор
// рисуемой фигуры
BOOL fRed; // флаг установки цвета
BOOL fGreen; // флаг установки цвета
BOOL fBlue; // флаг установки цвета
int id_bright; // установка интенсивности
};
// функция drawShape получает параметры по значению:
// hWnd - дескриптор окна
// hdc - дескриптор контекста устройства
// shapeData - иформация о рисуемой фигуре
// shapeSize - информация о размере фигуры
// bShow - информация о режиме (показать – не показать)
void drawShape (HWND hWnd, HDC hdc, SHAPE_DATA shapeData,
ShapeSize shapeSize, BOOL bShow)
{
if (bShow)
{
int intensity[3] = {100, 170, 255 };
int brightness = intensity [shapeData.id_bright - ID_DARK ];
// создаем кисть заданного цвета, запоминаем дескриптор кисти в hBrush
HBRUSH hBrush = CreateSolidBrush (RGB(
shapeData.fRed? brightness: 0,
shapeData.fGreen? brightness: 0,
shapeData.fBlue? brightness: 0)
);
// дескриптор новой кисти hBrush записываем в контекст устройства, дескриптор
// старой кисти сохраняем в holdBrush
HBRUSH holdBrush = (HBRUSH) SelectObject(hdc,hBrush);
RECT rect; // определение объекта rect типа RECT, где RECT стандартная
// структура, задающая координаты левого верхнего и правого
// нижнего угла прямоугольника, где
GetClientRect(hWnd, &rect); // получили размер клиентского окна
// в объекте rect с помощью стандартной функции
// определение центра фигуры (x0, y0) - всегда в центре клиентской области (окна)
int x0=rect.right /2, x1, x2;
int y0=rect.bottom /2, y1, y2;
// определение координат прямоугольника и эллипса
if (shapeSize == MIN)
{ x1 = x0 - W/2; y1 = y0 - H/2;
x2 = x0 + W/2; y2 = y0 + H/2;
}
else
{
x1 = y1 = 0;
x2 = rect.right; y2 = rect.bottom;
}
// определение координат ромба в массиве структур pt[4] типа POINT
POINT pt[4];
pt[0].x = (x1+x2) / 2; pt[0].y = y1;
pt[1].x = x2; pt[1].y = (y1+y2) / 2;
pt[2].x = (x1+x2) / 2; pt[2].y = y2;
pt[3].x = x1; pt[3].y = (y1+y2) / 2;
switch (shapeData.id_shape)
{
case ID_RECTANGLE:
Rectangle(hdc, x1,y1,x2,y2);
break;
case ID_RHOMB:
Polygon(hdc, pt,4);
break;
case ID_ELLIPSE:
Ellipse(hdc, x1,y1,x2,y2);
break;
}
// старую кисть возвращаем в контекст, кисть, которой рисовали - удаляем
DeleteObject(SelectObject(hdc,holdBrush));
} // конец тела if (bShow)
}
2. Создайте проект Win32 Project не пустой с именем – ваша_ фамилия1.
Система создала Вам минимальное приложение. Запустите проект.
Откройте двойным щелчком в окне Обозреватель решений в папке Заголовочные файлы файл Resource.h и ознакомьтесь с макросами, определенными с помощью директив препроцессора #define. Макросы были построены автоматически и задают идентификаторы ресурсов, таких как меню, подменю, иконки, заголовок приложения и другие объекты.
Откройте в окне Обозреватель решений в папке Файлы ресурсов с помощью любого текстового редактора, например редактора исходного текста, файл ваша_ фамилия1.rc и рассмотрите его. Найдите связь идентификаторов объектов ресурсов из файла Resource.h с описанием этих объектов в файле, который вы рассматриваете.
Вздохните облегченно, потому что вам не придется самим писать эти тексты. Тексты этих файлов будут строиться автоматически Редакторами ресурсов. (Но понимать эти тексты вы должны!)
Закройте окна файла Resource.h ифайла ваша_ фамилия1.rc
3. В окне Обозреватель решений откройте файл ваша_ фамилия1.rc двойным щелчком. В появившемся окне Окно ресурсов откройте папку Menu, щелкнув по его пункту IDC_MY (это идентификатор главного меню), и откройте Редактор меню.
Измените заголовки пунктов О программе…. (на О моей программе…), С правка ( на П омощь). Это можно сделать двумя способами:
- изменив название непосредственно в прямоугольнике пункта меню;
- вызвав диалоговое окно Свойства - окно свойств пункта (дважды щелкнуть по пункту меню) и изменив атрибут этого окна Надпись (Caption).
Сделайте изменения, применив оба способа. Запустите проект. Посмотрите изменения.
Модифицируйте главное меню. Добавьте новые пункты нулевого уровня, руководствуясь следующими таблицами.
Пункты главного меню (0-й уровень)
Имя пункта | Тип пункта | Идентификатор | Позиция |
&Файл | подменю | - | 0 (уже есть) |
&Видимость | подменю | - | |
&Рисовать | подменю | - | |
&Увеличить! | команда | IDM_RESIZE | |
С&правка | подменю | - | 4 (уже есть) |
Для того, чтобы сделать пункт меню пунктом-командой, в окне Свойств этого пункта необходимо изменить установку свойства Всплывающее меню с True на False Для пункта – команда в его окне Свойств сначала заполняйте поле ИД, и только после этого – поле Надпись. Это оградит вас от засорения файла Resource.h неправильными макросами с неиспользуемыми идентификаторами, которые строятся автоматически, как только вы заполнили поле Надпись!!!! |
Имя пункта «Увеличить!» завершается восклицательным знаком, чтобы информировать пользователя, что данный пункт главного меню является командой, а не заголовком подменю.
Добавьте пункты подменю первого уровня в пункты Файл, Видимость, Рисовать
Пункты подменю «Файл» (1-й уровень)
Имя пункта | Тип пункта | Идентификатор |
О&ткрыть | команда | IDM_OPEN |
&Закрыть | команда | IDM_CLOSE |
Со&хранить | команда | IDM_SAVE |
- | SEPARATOR | - |
В&ыход | команда | IDM_EXIT (уже есть) |
Пункты подменю «Видимость» (1-й уровень)
Имя пункта | Тип пункта | Идентификатор |
&Показать | команда | IDM_SHOW_SHAPE |
С&крыть | команда | IDM_HIDE_SHAPE |
Пункты подменю «Рисовать» (1-й уровень)
Имя пункта | Тип пункта | Идентификатор |
Фигура | подменю | - |
Цвет | подменю | - |
Будьте внимательны. Пункты подменю 1 уровня по умолчанию создаются как команды. Для того, чтобы сделать пункт меню пунктом-подменю, в окне Свойств этого пункта необходимо сначала изменить установку свойства Всплывающее меню с False на True Поле ИД будет сделано недоступным, что оградит вас от засорения файла Resource.h неправильными макросами с неиспользуемыми идентификаторами, которые строятся автоматически, как только вы заполнили поле Надпись!!!! |
Пункты подменю «Справка» (1-й уровень) – уже есть
Имя пункта | Тип пункта | Идентификатор |
О программе … | команда | IDM_ABOUT |
Добавьте пункты подменю второго уровня в пункты Фигура и Цвет
Пункты подменю «Фигура» (2-й уровень)
Имя пункта | Тип пункта | Идентификатор |
Прямоугольник | команда | ID_RECTANGLE |
Ромб | команда | ID_RHOMB |
Эллипс | команда | ID_ELLIPSE |
Пункты подменю «Цвет» (2-й уровень)
Имя пункта | Тип пункта | Идентификатор |
Красный | команда | ID_RED |
Зеленый | команда | ID_GREEN |
Синий | команда | ID_BLUE |
- | SEPARATOR | - |
Темный | команда | ID_DARK |
Средний | команда | ID_MEDIUM |
Светлый | команда | ID_LIGHT |
Откройте снова файлы Resource.h и ваша_ фамилия1.rc и рассмотрите изменения в них.
Запустите проект. Пункты меню есть в приложении, теперь надо организовать реакции приложения на соответствующие команды.
4. Откройте файл ваша_ фамилия1.h и добавьте в него макросы W и H, перечисление
enum ShapeSize, а также структуру SHAPE_DATA.
#define W 200 // фиксированная ширина фигуры
#define H 140 // фиксированная высота фигуры
enum ShapeSize { MIN, MAX }; // именованная константа MIN = 0, MAX = 1
struct SHAPE_DATA {
int id_shape; // целое, определяет идентификатор
// рисуемой фигуры
BOOL fRed; // флаг установки цвета
BOOL fGreen; // флаг установки цвета
BOOL fBlue; // флаг установки цвета
int id_bright; // установка интенсивности
};
Создайте в проекте новый файл drawShape.cpp, запишите в него текст функции
drawShape.
Перед функцией пропишите две директивы препроцессора
#include "stdafx.h"
#include "ФамилияСтудента.h"
Откомпилируйте созданный файл
5. Откройте файл ваша_ фамилия1.cpp. Прототип функции drawShape запишите в файле ваша_ фамилия1. cpp
Внесите изменения в функцию WndProc, в ту ее часть, где происходит обработка сообщений – команд WM_CREATE, WM_COMMAND и WM_PAINT, организующие обработку сообщений от созданных пунктов меню. Создайте ветви case для обработки сообщений WM_COMMAND, пришедших от пунктов – команд добавленных вами в меню.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
// добавьте описания объектов, которые инициализируются сначала своими
// начальными значениями, определяющими исходное поведение функции drawShape.
// В процессе работы приложения эти значения должны меняться по указанию
// пользователя и изменять поведение функции drawShape
static ShapeSize shapeSize = MIN;
static BOOL bShow = TRUE;
static SHAPE_DATA shapeData = { ID_RECTANGLE, TRUE, FALSE, FALSE, ID_DARK};
static HMENU hMenu = GetMenu(hWnd); // стандартная функция
// GetMenu возвращает дескриптор главного меню
// Обратите внимание на определение объектов с ключевым словом static.
// Объекты, определенные как static, имеют область видимости как локальные объекты,
// т. е. они видны только в блоке, их ограничивающем, но живут, как и глобальные
// объекты – все время работы приложения. Их инициализация, в отличие от локальных
// объектов осуществляется только один раз, при первом входе в блок, их
// ограничивающий. Эти объекты «помнят» свои значения и при выходе из функции,
// в которой они определены.
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case IDM_OPEN:
// функция MessageBox вызывает диалоговое окно
// с соответствующим сообщением
MessageBox (hWnd, TEXT("выбран пункт 'Открыть ' "),
TEXT("меню 'Файл' "), MB_OK);
break;
case IDM_CLOSE:
MessageBox(hWnd, TEXT("выбран пункт 'Закрыть ' "),
TEXT("меню 'Файл '"), MB_OK);
break;
case IDM_SAVE:
MessageBox(hWnd, TEXT("выбран пункт 'Сохранить ' "),
TEXT("меню ’Файл’ "), MB_OK);
break;
case IDM_SHOW_SHAPE:
bShow = TRUE;
break;
case IDM_HIDE_SHAPE:
bShow = FALSE;
break;
case ID_RECTANGLE:
shapeData.id_shape = ID_RECTANGLE;
break;
case ID_RHOMB:
shapeData.id_shape = ID_RHOMB;
break;
case ID_ELLIPSE:
shapeData.id_shape = ID_ELLIPSE; break;
case ID_RED:
shapeData.fRed= TRUE;
shapeData.fGreen =FALSE;
shapeData.fBlue=FALSE;
break;
case ID_GREEN:
shapeData.fRed=FALSE;
shapeData.fGreen =TRUE;
shapeData.fBlue=FALSE;
break;
case ID_BLUE:
shapeData.fRed=FALSE;
shapeData.fGreen = FALSE;
shapeData.fBlue=TRUE;
break;
case ID_DARK:
shapeData.id_bright = ID_DARK;
break;
case ID_MEDIUM:
shapeData.id_bright = ID_MEDIUM;
break;
case ID_LIGHT:
shapeData.id_bright = ID_LIGHT;
break;
case IDM_RESIZE:
// пока не обрабатываем команду!!!!!!!!
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
// Вызов очень важной InvalidateRect функции, после того, как произведены изменения
// значений параметров функции drawShape
// функция InvalidateRect, посылая сообщение WM_PAINT, перерисовывает клиентскую // область окна с дескриптором hWnd
InvalidateRect(hWnd,NULL,TRUE);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...