Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ИГС / Labor_01.doc
Скачиваний:
13
Добавлен:
17.04.2018
Размер:
524.8 Кб
Скачать

Обработка сообщений меню Windows программы

Следующим шагом будет компиляция файла ресурсов. В файле MenuWin.rc содержится код ресурсов написанный по правилам языка высокоуровневого программирования. Теперь этот код надо перевести в коды машинного языка.

В окне Resource View выделяем файл MenuWin.rc и затем в главном меню проходим по цепочке Build – Compile. Если компиляция прошла успешно, то в каталоге проекта D:\BC-WORK\MenuWin\Debug появится файл MenuWin.res. Этот файл будет использовать компоновщик на стадии создания исполняемого файла MenuWin.exe.

Построим проект, пройдясь по цепочке Build – Rebuild MenuWin. Запустим программу на выполнения и увидим все туже картину Рис.6. Ничего не изменилось, потому что не было указано, к какому окну относится созданное меню.

Для активизации меню изменим немного код в файле MenuWin.cpp. В начале файла подключим заголовочный файл resource.h.

#include "resource.h"

В пункте регистрации класса окна изменим строчку, связанную с меню.

wc.lpszMenuName = (LPCTSTR)MENU1;

Теперь снова компилируем и запускаем программу. Результат работы программы показан на следующем рисунке.

Рис.17

Результат работы программы MenuWin.exe.

Действительно, в окне появилось меню, и это меню активизировано. Только меню пока работает вхолостую. Нажатие кнопок меню не приводит, к каким либо действиям. Необходимо самим осуществить обработку сообщений, приходящих к окну при нажатии кнопок созданного меню.

Создадим план работы меню. Пусть нажатие кнопки Exit приводит к закрытию окна, а нажатие кнопок Ellipse и Polygon приводит к рисованию эллипса и полигона соответственно. Для этого добавим в функцию окна WndProc следующие строчки кода.

switch(message)

{

//сообщения от кнопок меню

case WM_COMMAND:

switch(LOWORD(wParam))

{

case ID_EXIT:

PostQuitMessage(0);

break;

case ID_ELLIPSE:

Ellipse_OnDC(hWnd);

break;

case ID_POLYGON:

Polygon_OnDC(hWnd);

break;

}

break;

}

Нам понадобятся две функции Ellipse_OnDC и Polygon_OnDC для обработки нажатия кнопок ELLIPSE и POLYGON.

В начало файла MenuWin.cpp добавим прототипы этих функций.

void Polygon_OnDC(HWND);

void Ellipse_OnDC(HWND);

Кроме того определим структуру

struct POINT2 {

double x, y;

};

Ниже приводится определение функции Polygon_OnDC.

void Polygon_OnDC(HWND hwnd)

{

RECT rc;

GetClientRect(hwnd,&rc); //дает размеры клиентской области окна <hwnd>

//размеры окна в мировых координатах и в пикселях

xLeft = -10; xRight = 10; yBottom = -6; yTop = 6;

nLeft = rc.left; nRight = rc.right; mBottom = rc.bottom; mTop = rc.top;

double masht; //коэффициент угловой деформации при переходе

//от мировых к экранным координатам

masht = (xRight-xLeft)*(mBottom-mTop)/(yTop-yBottom)/(nRight-nLeft);

HDC hdc;

hdc = GetDC(hwnd);

HBRUSH hbrush, hbrushOld;

HPEN hpen1, hpen2, hpenOld;

hpen1 = CreatePen(PS_SOLID,1,RGB(0,255,255));

hpenOld = (HPEN)SelectObject(hdc,hpen1);

int nb, ne, mb, me;

//рисуем ось OX

nb = xn(xLeft); mb = ym(0);

MoveToEx(hdc, nb, mb, NULL);

ne = xn(xRight); me = ym(0);

LineTo(hdc,ne,me);

//рисуем ось OY

nb = xn(0); mb = ym(yBottom);

MoveToEx(hdc, nb, mb, NULL);

ne = xn(0); me = ym(yTop);

LineTo(hdc,ne,me);

POINT2 Vt[4];

Vt[0].x = -7; Vt[0].y = -4;

Vt[1].x = -5; Vt[1].y = 4;

Vt[2].x = 7; Vt[2].y = 3;

Vt[3].x = 3; Vt[3].y = -2;

POINT P[4];

for(int i=0; i<4; i++)

{

P[i].x = xn(Vt[i].x); P[i].y = ym(Vt[i].y);

}

hpen2 = CreatePen(PS_SOLID,2,RGB(255,0,0));

SelectObject(hdc,hpen2);

hbrush = CreateSolidBrush(RGB(0,200,255));

hbrushOld = (HBRUSH)SelectObject(hdc,hbrush);

Polygon(hdc, P, 4);

SelectObject(hdc,hbrushOld);

DeleteObject(hbrush);

SelectObject(hdc,hpenOld);

DeleteObject(hpen1);

DeleteObject(hpen2);

LOGFONT lf;

HFONT hFont, hFontOld;

double dx, dy, alf;

for(int j=0; j<3; j++)

{

dx = Vt[j+1].x - Vt[j].x;

dy = Vt[j+1].y - Vt[j].y;

alf = atan2(dy*masht,dx);

memset(&lf, 0, sizeof(LOGFONT));

wcscpy_s(lf.lfFaceName, L"Courier New");

lf.lfHeight = 18;

lf.lfWeight = FW_BOLD;

lf.lfEscapement = LONG(573*alf);

hFont = CreateFontIndirect(&lf);

if(j == 0)

hFontOld = (HFONT)SelectObject(hdc, hFont);

else

SelectObject(hdc, hFont);

SetBkColor(hdc,RGB(192,192,192));

SetTextColor(hdc,RGB(255,255,255));

TextOut(hdc,xn(Vt[j].x - 1.25*sin(alf)),

ym(Vt[j].y + 1.25*cos(alf)), _T(" Polygon "),9);

}

SelectObject(hdc, hFontOld);

DeleteObject(hFont);

ReleaseDC(hwnd, hdc);

}

Заметим, что в этой функции размеры окна вывода совпадают с размерами клиентской области окна. Для получения размеров клиентской области применяется API-функция GetClientRect. Надписи сделаны шрифтом "Courier New" и выводятся в цикле параллельно сторонам полигона.

Ниже приводится определение функции Ellipse_OnDC.

void Ellipse_OnDC(HWND hwnd)

{

RECT rc;

GetClientRect(hwnd,&rc); //дает размеры клиентской области окна <hwnd>

//размеры окна в мировых координатах и в пикселях

xLeft = -10; xRight = 10; yBottom = -6; yTop = 6;

nLeft = (5*rc.left + rc.right)/6;

nRight = (5*rc.right + rc.left)/6;

mBottom = (7*rc.bottom + rc.top)/8;

mTop = (7*rc.top + rc.bottom)/8;

HDC hdc = GetDC(hwnd);

//создание прямоугольной области поля вывода

HRGN hrgn1 = CreateRectRgn(nLeft,mTop,nRight,mBottom);

//заливаем выделенную область белым цветом

HBRUSH hbrush1 = CreateSolidBrush(RGB(0xFF,0xFF,0xFF));

FillRgn(hdc,hrgn1,hbrush1);

//ограничиваем область вывода изображения

SelectClipRgn(hdc,hrgn1);

LOGFONT lf;

HFONT hFont1, hFontOld;

//создаем шрифт, выбираем его в контекст устройства и рисуем надпись

memset(&lf, 0, sizeof(LOGFONT));

strcpy(lf.lfFaceName, "Arial");

lf.lfHeight = 45;

lf.lfWeight = FW_BOLD;

lf.lfEscapement = 900;

hFont1 = CreateFontIndirect(&lf);

hFontOld = (HFONT)SelectObject(hdc, hFont1);

TextOut(hdc,xn(-5), ym(-2), " E l l i p s e ",15);

HPEN hpen1, hpenOld;

hpen1 = CreatePen(PS_SOLID,1,RGB(0,255,255));

hpenOld = (HPEN)SelectObject(hdc,hpen1);

int nb, ne, mb, me;

//рисуем ось OX

nb = xn(xLeft); mb = ym(0);

MoveToEx(hdc, nb, mb, NULL);

ne = xn(xRight); me = ym(0);

LineTo(hdc,ne,me);

//рисуем ось OY

nb = xn(0); mb = ym(yBottom);

MoveToEx(hdc, nb, mb, NULL);

ne = xn(0); me = ym(yTop);

LineTo(hdc,ne,me);

//размеры эллипса

double x1 = -4, x2 = 12, y1 = 4, y2 = -4;

HPEN hpen2 = CreatePen(PS_SOLID,2,RGB(255,0,0));

SelectObject(hdc,hpen2);

HBRUSH hbrush2, hbrushOld;

hbrush2 = CreateSolidBrush(RGB(0,200,255));

hbrushOld = (HBRUSH)SelectObject(hdc,hbrush2);

Ellipse(hdc, xn(x1), ym(y1), xn(x2), ym(y2));

//восстанавливаем контекст по умолчанию и уничтожаем созданные GDI-объекты

SelectObject(hdc,hbrushOld);

DeleteObject(hbrush1);

DeleteObject(hbrush2);

SelectObject(hdc,hpenOld);

DeleteObject(hpen1);

DeleteObject(hpen2);

SelectObject(hdc, hFontOld);

DeleteObject(hFont1);

DeleteObject(hrgn1);

ReleaseDC(hwnd, hdc);

}

В этой функции поле вывода создается с помощью API- функций CreateRectRgn и SelectClipRgn. Эти функции позволяют создавать область вывода изображения с отсечением. В приведенном примере, часть эллипса отсекается.

Теперь снова компилируем и запускаем программу. Результат работы программы при нажатии кнопки меню Polygon, показан на следующем рисунке.

Рис.18

Результат работы пункта меню Polygon, программы MenuWin.exe.

Результат работы программы при нажатии кнопки меню Ellipse, показан на другом рисунке.

Рис.19

Результат работы пункта меню Ellipse, программы MenuWin.exe.

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

Рис.20

Результат работы программы MenuWin.exe, с наложением одного изображения на другое.

Заметим, что этот эффект возникает, когда для работы с контекстом окна применяется пара функций GetDC() и ReleaseDC(). Если для работы с контекстом окна использовать другую пару функций BeginPaint() и EndPaint(), то такого эффекта не наблюдается. Дело в том, что две последние функции применяются при обработке сообщения WM_PAINT. В этом случае окно сначала очищается, а затем рисуется новое изображение. Поэтому при работе с первыми двумя функциями для очистки окна нужно предпринять дополнительные действия.

Можно поступить следующим образом. Перед рисованием нового изображения производится закрашивание клиентской области окна цветом фона.

HRGN hrgn1 = CreateRectRgn(nLeft,mTop,nRight,mBottom);

HBRUSH hbrush1 = CreateSolidBrush(RGB(0xC0,0xC0,0xC0));

FillRgn(hdc,hrgn1,hbrush1);

DeleteObject(hbrush1);

DeleteObject(hrgn1);

Существует другой более элегантный способ очистки окна, надо самим посылать окну сообщение WM_PAINT. Для этого надо ввести еще одну кнопку меню Clean, при нажатии на которую окно будет очищаться. Войдем в редактор меню. Добавим еще один пункт с идентификатором ID_CLEAN. В функции окнаWndProc добавим несколько строчек кода.

case WM_COMMAND:

switch(LOWORD(wParam))

{

case ID_EXIT:

PostQuitMessage(0);

break;

case ID_CLEAN:

InvalidateRect(hWnd, NULL, TRUE);

break;

case ID_ELLIPSE:

Ellipse_OnDC(hWnd);

break;

case ID_POLYGON:

Polygon_OnDC(hWnd);

break;

}

break;

Здесь обратим внимание на функцию InvalidateRect(), при вызове этой функции посылается окну сообщение и клиентская область окна очищается.

Соседние файлы в папке ИГС