Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_I.pdf
Скачиваний:
96
Добавлен:
05.06.2014
Размер:
4.61 Mб
Скачать

219

PostQuitMessage(0); return 0;

}

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

}

Рис. 6.6 Программа CHECKER2

Логика обработки сообщения WM_KEYDOWN в программе CHECKER2 следующая: определяется положение курсора (GetCursorPos), координаты экрана преобразуются в координаты рабочей области (ScreenToClient), а затем координаты делятся на ширину и высоту прямоугольного блока. Полученные значения х и у показывают положение прямоугольника в массиве 5 на 5. Курсор мыши при нажатии клавиши не всегда находится в рабочей области, поэтому х и у должны быть обработаны макросами min и max таким образом, чтобы гарантировать их попадание в диапазон от 0 до 4.

Для клавиш со стрелками программа CHECKER2 увеличивает или уменьшает на 1 соответственно значение х или у. Если нажатой клавишей является клавиша <Enter> (VK_RETURN) или клавиша <Spacebar> (VK_SPACE), то программа CHECKER2 использует функцию SendMessage для посылки себе же синхронного сообщения WM_LBUTTONDOWN. Такая технология напоминает метод, использованный в программе SYSMETS в главе 5, где для полосы прокрутки окна в программу добавлен интерфейс клавиатуры. Логика обработки сообщения WM_KEYDOWN заканчивается расчетом координат рабочей области, которые являются координатами центра прямоугольника, преобразованием их в координаты экрана (ClientToScreen) и установкой положения курсора

(SetCursorPos).

Использование дочерних окон для тестирования попадания

В некоторых программах, например в программе Windows PAINT, рабочая область окна делится на более мелкие логические области. Программа PAINT, окно которой представлено на рис. 6.7, имеет слева область меню со значками, а внизу область меню выбора цветов.

Рис. 6.7 Программа Windows PAINT

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

А можно иначе. В действительности, в программе PAINT рисование меню и тестирование попадания упрощается, благодаря использованию "дочерних окон" (child windows). Дочерние окна делят рабочую область на несколько более мелких участков. Каждое дочернее окно имеет собственный описатель окна, оконную процедуру и рабочую область. Каждая оконная процедура получает сообщения мыши, которые относятся только к его дочернему окну. Параметр lParam в сообщении мыши содержит координаты, заданные относительно верхнего левого угла рабочей области дочернего, а не родительского окна.

Дочерние окна, используемые таким образом, помогают сделать ваши программы более структурированными и модульными. Если дочерние окна используют разные классы окна, то каждое дочернее окно может иметь собственную оконную процедуру. Для разных классов окна могут также определяться и разный цветовой фон и разные, задаваемые по умолчанию, курсоры. В главе 8, мы рассмотрим "дочерние окна управления" (child window

220

controls) — предопределенные дочерние окна, имеющие форму полос прокрутки, кнопок и окон редактирования. А сейчас давайте рассмотрим, как можно использовать дочерние окна в программе CHECKER.

Дочерние окна в программе CHECKER

На рис. 6.8 представлена программа CHECKER3. В этой версии программы для обработки щелчков мыши создаются 25 дочерних окон. Здесь отсутствует интерфейс клавиатуры, но он может быть легко добавлен.

В программе CHECKER3 имеется две оконные процедуры, которые называются WndProc и ChildWndProc. WndProc — это по-прежнему оконная процедура главного (или родительского) окна. ChildWndProc — это оконная процедура 25 дочерних окон. Обе оконные процедуры должны быть определены как функции обратного вызова

(CALLBACK).

Поскольку оконная процедура задается в структуре класса окна, которую вы регистрируете в Windows с помощью функции RegisterClassEx, то для двух оконных процедур в программе CHECKER3.С требуется два класса окна. Первый класс окна — это класс главного окна, и называется он "Checker3". Второму классу окна назначено имя

"Checker3_Child".

Большинство полей структурной переменной wndclass просто повторно используются при регистрации класса

"Checker3_Child" в WinMain. Поле lpszClassName устанавливается в "Checker3_Child" (имя класса). Поле lpfnWndProc устанавливается в ChildWndProc — оконную процедуру этого класса, а поля hIcon и hIconSm устанавливаются в NULL, поскольку с дочерними окнами значки не используются. Для класса окна "Checker3_Child" поле cbWndExtra структурной переменной wndclass устанавливается равной 2 байтам, или точнее, sizeof(WORD). Это поле требует от Windows зарезервировать 2 байта дополнительного пространства в структуре, которую Windows строит для каждого окна, создаваемого на основе данного класса окна. Вы можете использовать это пространство для хранения информации, которая может быть индивидуальной для каждого окна.

CHECKER3.MAK

#------------------------

# CHECKER3.MAK make file

#------------------------

checker3.exe : checker3.obj

$(LINKER) $(GUIFLAGS) -OUT:checker3.exe checker3.obj $(GUILIBS)

checker3.obj : checker3.c $(CC) $(CFLAGS) checker3.c

CHECKER3.C

/*-------------------------------------------------

 

CHECKER3.C --

Mouse Hit-Test Demo Program No. 3

 

(c) Charles Petzold, 1996

-------------------------------------------------

*/

#include <windows.h>

#define DIVISIONS 5

#define MoveTo(hdc, x, y) MoveToEx(hdc, x, y, NULL)

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

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

char

szChildClass[] = "Checker3_Child";

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

{

static char szAppName[] = "Checker3";

HWND

hwnd;

MSG

msg;

WNDCLASSEX

wndclass;

wndclass.cbSize

= sizeof(wndclass);

wndclass.style

= CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc

= WndProc;

221

wndclass.cbClsExtra

= 0;

wndclass.cbWndExtra

= 0;

wndclass.hInstance

= hInstance;

wndclass.hIcon

= LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor

= LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground

=(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName

= NULL;

wndclass.lpszClassName

= szAppName;

wndclass.hIconSm

= LoadIcon(NULL, IDI_APPLICATION);

RegisterClassEx(&wndclass);

wndclass.lpfnWndProc

= ChildWndProc;

wndclass.cbWndExtra

= sizeof(WORD);

wndclass.hIcon

= NULL;

wndclass.lpszClassName

= szChildClass;

wndclass.hIconSm

= NULL;

RegisterClassEx(&wndclass);

hwnd = CreateWindow(szAppName, "Checker3 Mouse Hit-Test Demo", WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, iCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

static HWND hwndChild[DIVISIONS][DIVISIONS];

int cxBlock, cyBlock, x, y;

switch(iMsg)

{

case WM_CREATE :

for(x = 0; x < DIVISIONS; x++) for(y = 0; y < DIVISIONS; y++)

{

hwndChild[x][y] = CreateWindow(szChildClass, NULL, WS_CHILDWINDOW | WS_VISIBLE,

0, 0, 0, 0, hwnd,(HMENU)(y << 8 | x),

(HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),

NULL);

}

return 0;

case WM_SIZE :

cxBlock = LOWORD(lParam) / DIVISIONS; cyBlock = HIWORD(lParam) / DIVISIONS;

for(x = 0; x < DIVISIONS; x++) for(y = 0; y < DIVISIONS; y++)

MoveWindow(hwndChild[x][y],

222

x * cxBlock, y * cyBlock, cxBlock, cyBlock, TRUE);

return 0;

case WM_LBUTTONDOWN : MessageBeep(0); return 0;

case WM_DESTROY : PostQuitMessage(0); return 0;

}

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

}

LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

HDC hdc;

PAINTSTRUCT ps;

RECT rect;

switch(iMsg)

{

case WM_CREATE :

SetWindowWord(hwnd, 0, 0); // on/off flag return 0;

case WM_LBUTTONDOWN :

SetWindowWord(hwnd, 0, 1 ^ GetWindowWord(hwnd, 0));

InvalidateRect(hwnd, NULL, FALSE);

return 0;

case WM_PAINT :

hdc = BeginPaint(hwnd, &ps);

GetClientRect(hwnd, &rect);

Rectangle(hdc, 0, 0, rect.right, rect.bottom);

if(GetWindowWord(hwnd, 0))

 

{

 

MoveTo(hdc, 0,

0);

LineTo(hdc, rect.right,

rect.bottom);

MoveTo(hdc, 0,

rect.bottom);

LineTo(hdc, rect.right, 0);

}

EndPaint(hwnd, &ps); return 0;

}

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

}

Рис. 6.8 Программа CHECKER3

Вызов функции CreateWindow в WinMain создает на основе класса "Checker3" главное окно. Это нормально. Однако, когда WndProc получает сообщение WM_CREATE, она, чтобы создать 25 дочерних окон на основе класса "Checker3_Child", 25 раз вызывает функцию CreateWindow. В следующей таблице дано сравнение параметров вызова функции CreateWindow в WinMain, создающей главное окно и вызова функции CreateWindow в WndProc, создающей 25 дочерних окон.

Параметр

Главное окно

Дочернее окно

класс окна

"Checker3"

"Checker3_Child"

заголовок окна

"Checker3... "

NULL

стиль окна

WS_OVERLAPPEDWINDOW

WS_CHILDWINDOW| WS_VISIBLE

Соседние файлы в предмете Операционные системы