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

223

Параметр

Главное окно

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

положение

CW_USEDEFAULT

0

по горизонтали

 

 

положение

CW_USEDEFAULT

0

по вертикали

 

 

ширина

CW_USEDEFAULT

0

высота

CW_USEDEFAULT

0

описатель

NULL

hwnd

родительского окна

 

 

описатель меню/

NULL

(HMENU)(y << 8 | x)

идентификатор

 

 

дочернего окна

hInstance

(HINSTANCE) GetWindowLong (hwnd,

описатель

экземпляра

 

GWL_HINSTANCE)

дополнительные

NULL

NULL

параметры

 

 

Обычно для дочерних окон требуются параметры положения, ширины и высоты, но в программе CHECKER3 положение и размер дочерних окон устанавливаются позже в WndProc. Описатель родительского окна для главного окна равен NULL, поскольку оно родительское. Описатель родительского окна необходим при вызове функции CreateWindow для создания дочернего окна.

В главном окне отсутствует меню, поэтому соответствующий параметр равен NULL. Для дочерних окон этот же параметр называется "идентификатором дочернего окна" (child ID). Это число уникально для каждого дочернего окна. Идентификатор дочернего окна приобретает важное значение при управлении дочерними окнами, поскольку сообщения для родительского окна, как мы увидим в главе 8, идентифицируются этим идентификатором дочернего окна. В программе CHECKER3 идентификаторы дочерних окон установлены так, чтобы они соответствовали положению, которое каждое дочернее окно занимает в массиве 5 на 5 внутри главного окна.

Описателем экземпляра в обоих классах является hInstance. Когда создается дочернее окно, значение hInstance извлекается из структуры, которую Windows поддерживает для окна, с помощью функции GetWindowLong. (Вместо функции GetWindowLong можно было бы сохранить значение hInstance в глобальной переменной и непосредственно его использовать.)

Каждое дочернее окно имеет свой описатель окна, который хранится в массиве hwndChild. Когда WndProc получает сообщение WM_SIZE, она вызывает функцию MoveWindow для каждого из 25 дочерних окон. Параметры задают верхний левый угол дочернего окна относительно начала координат рабочей области родительского окна, ширину и высоту дочернего окна, а также необходимость перерисовки дочернего окна.

Теперь давайте рассмотрим ChildWndProc. Эта оконная процедура обрабатывает сообщения для всех 25 дочерних окон. Параметр hwnd для ChildWndProc является описателем дочернего окна, получающего сообщение. Когда ChildWndProc обрабатывает сообщение WM_CREATE (что происходит 25 раз, поскольку имеется 25 дочерних окон), она использует функцию SetWindowWord для хранения 0 в дополнительном пространстве, зарезервированном внутри структуры окна. (Вспомните, что мы зарезервировали это пространство с помощью поля cbWndExtra при определении структуры класса окна.) ChildWndProc использует это значение для хранения текущего состояния прямоугольника (зачеркнут он символом Х или нет). Когда в дочернем окне происходит щелчок мыши, логика обработки сообщения WM_LBUTTONDOWN просто изменяет значение этого слова (0 на 1 или 1 на 0) и делает недействительной всю рабочую область дочернего окна. Эта область и является тем самым прямоугольником, в котором произошел щелчок. Обработка сообщения WM_PAINT вполне обычна, поскольку размер рисуемого прямоугольника равен размеру рабочей области окна.

Поскольку файл с текстом исходной программы на С и исполняемый файл .EXE программы CHECKER3 больше, чем аналогичные файлы для программы CHECKER1, то не будем утверждать, что CHECKER3 "проще", чем CHECKER1. Но обратите внимание, что нам больше не нужно делать никакого тестирования попадания для мыши! Если какое-нибудь дочернее окно в программе CHECKER3 получает сообщение WM_LBUTTONDOWN, то значит в этом окне и было нажатие, и это все, что ему нужно знать.

Если вы хотите добавить к программе CHECKER3 интерфейс клавиатуры, запомните, что главное окно попрежнему получает сообщения клавиатуры, поскольку оно имеет фокус ввода. Более подробно дочерние окна мы рассмотрим в главе 8.

Захват мыши

Оконная процедура обычно получает сообщения мыши только тогда, когда курсор мыши находится в рабочей или в нерабочей области окна. Но программе может понадобиться получать сообщения мыши и тогда, когда курсор мыши находится вне окна. Если это так, то программа может произвести "захват" (capture) мыши.

224

Рисование прямоугольника

Для того, чтобы понять, для чего может понадобиться захват мыши, давайте рассмотрим программу BLOKOUT1, представленную на рис. 6.9.

BLOKOUT1.MAK

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

# BLOKOUT1.MAK make file

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

blokout1.exe : blokout1.obj

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

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

BLOKOUT1.C

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

 

BLOKOUT1.C --

Mouse Button Demo Program

 

(c) Charles Petzold, 1996

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

*/

#include <windows.h>

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

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

{

static char szAppName[] = "BlokOut1";

HWND

hwnd;

MSG

msg;

WNDCLASSEX

wndclass;

wndclass.cbSize

= sizeof(wndclass);

wndclass.style

= CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc

= WndProc;

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

hwnd = CreateWindow(szAppName, "Mouse Button 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;

}

225

void DrawBoxOutline(HWND hwnd, POINT ptBeg, POINT ptEnd)

{

HDC hdc;

hdc = GetDC(hwnd);

SetROP2(hdc, R2_NOT);

SelectObject(hdc, GetStockObject(NULL_BRUSH));

Rectangle(hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y);

ReleaseDC(hwnd, hdc);

}

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

{

static BOOL fBlocking, fValidBox;

static POINT ptBeg, ptEnd, ptBoxBeg, ptBoxEnd; HDC hdc;

PAINTSTRUCT ps; switch(iMsg)

{

case WM_LBUTTONDOWN :

ptBeg.x = ptEnd.x = LOWORD(lParam); ptBeg.y = ptEnd.y = HIWORD(lParam);

DrawBoxOutline(hwnd, ptBeg, ptEnd);

SetCursor(LoadCursor(NULL, IDC_CROSS));

fBlocking = TRUE; return 0;

case WM_MOUSEMOVE : if(fBlocking)

{

SetCursor(LoadCursor(NULL, IDC_CROSS));

DrawBoxOutline(hwnd, ptBeg, ptEnd);

ptEnd.x = LOWORD(lParam); ptEnd.y = HIWORD(lParam);

DrawBoxOutline(hwnd, ptBeg, ptEnd);

}

return 0;

case WM_LBUTTONUP : if(fBlocking)

{

DrawBoxOutline(hwnd, ptBeg, ptEnd);

ptBoxBeg

= ptBeg;

ptBoxEnd.x

= LOWORD(lParam);

ptBoxEnd.y

= HIWORD(lParam);

SetCursor(LoadCursor(NULL, IDC_ARROW));

fBlocking = FALSE;

fValidBox = TRUE;

InvalidateRect(hwnd, NULL, TRUE);

}

return 0;

226

case WM_CHAR :

if(fBlocking & wParam == '\x1B') // ie, Escape

{

DrawBoxOutline(hwnd, ptBeg, ptEnd);

SetCursor(LoadCursor(NULL, IDC_ARROW));

fBlocking = FALSE;

}

return 0;

case WM_PAINT :

hdc = BeginPaint(hwnd, &ps);

if(fValidBox)

{

SelectObject(hdc, GetStockObject(BLACK_BRUSH));

Rectangle(hdc, ptBoxBeg.x, ptBoxBeg.y,

ptBoxEnd.x, ptBoxEnd.y);

}

if(fBlocking)

{

SetROP2(hdc, R2_NOT);

SelectObject(hdc, GetStockObject(NULL_BRUSH));

Rectangle(hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y);

}

EndPaint(hwnd, &ps); return 0;

case WM_DESTROY : PostQuitMessage(0); return 0;

}

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

}

Рис. 6.9 Программа BLOKOUT1

Эта программа показывает немногое из того, что могло бы быть реализовано в программе рисования в Windows. Вы начинаете рисовать, нажимая левую кнопку мыши, чтобы указать один из углов прямоугольника, и удерживая кнопку нажатой, вы двигаете мышь. Программа рисует контур прямоугольника, со вторым противоположным углом в текущей позиции курсора. После отпускания кнопки мыши, программа закрашивает прямоугольник. На рис. 6.10 показаны два прямоугольника, один из которых уже нарисован, а второй находится в процессе рисования.

При нажатии левой кнопки мыши, программа BLOKOUT1 сохраняет координаты мыши и первый раз вызывает функцию DrawBoxOutline. Функция рисует прямоугольник с использованием растровой операции R2_NOT, которая меняет цвет рабочей области на противоположный. При обработке последующих сообщений WM_MOUSEMOVE программа снова рисует такой же прямоугольник, полностью стирая предыдущий. Затем она использует новые координаты мыши для рисования нового прямоугольника. Наконец, когда программа BLOKOUT1 получает сообщение WM_LBUTTONUP, координаты мыши сохраняются, и окно делается недействительным, генерируя сообщение WM_PAINT для вывода на экран полученного прямоугольника.

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