на тему рефераты Информационно-образоательный портал
Рефераты, курсовые, дипломы, научные работы,
на тему рефераты
на тему рефераты
МЕНЮ|
на тему рефераты
поиск
Ознакомление с приложениями Windows
p align="left">В некоторых случаях при описании стиля окна необходимо задавать дополнительные характеристики, которые не входят в состав параметра dwStyle. Так, например, Вы можете создать окно, которое всегда находится поверх всех остальных окон (always on top, topmost). Для этого используется дополнительное двойное слово стиля (extended style) и, соответственно, другая функция для создания окна:

HWND CreateWindowEx(
dwExStyle, lpszClassName, lpszWindowName, dwStyle,
nX, nY, nWidth, nHeight,
hWndParent, hMenu, hInstance, lpParam
);

Эта функция отличается только наличием еще одного параметра dwExStyle, задающего дополнительные стили окна. Для задания этих стилей используются мнемонические имена с префиксом WS_EX_..., например WS_EX_TOPMOST или WS_EX_TRANSPARENT.

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

Однако в WinMain не рекомендуется создавать сразу видимое окно. Это связано с тем, что приложение может быть запущено в начально минимизированном состоянии. Как надо отобразить окно мы можем узнать через аргумент nCmdShow функции WinMain, но использовать его функцией CreateWindow сложно. Поэтому окно создается невидимым и затем отображается в требуемом нам виде:

ShowWindow( hWnd, nCmdShow );
UpdateWindow( hWnd );

Функция ShowWindow указывает окну, в каком виде оно должно быть отображено на экране. В функции WinMain параметр nCmdShow берется из переданных аргументов -- он определяет, каким образом пользователь хочет запустить это приложение. Во время выполнения функции ShowWindow на экране отображается рамка и заголовок окна в нужном месте и требуемого размера.

Во время выполнения функции UpdateWindow отображается внутренняя область окна. Определимся, что внутренняя область окна иногда называется клиентной (client), а рамка, заголовок, или заменяющая все пиктограмма называются внешней областью, обрамлением (frame) или неклиентной (non-client) областью окна. Для отображения внутренней области окна приложение получает специальное сообщение, обработчик которого выполняет требуемое рисование.

Цикл обработки сообщений

Сейчас нам придется обзорно рассмотреть механизм передачи сообщений в Windows 3.x (реально он гораздо сложнее, особенно в Windows-95 или Windows NT). Для начала следует выделить некоторый источник сообщений. Им может являться какое-либо устройство ввода (например, клавиатура, мышь), специальные устройства (типа таймера), либо какое-либо работающее приложение. Сообщения, полученные от источника сообщений, накапливаются в очереди сообщений (message queue). Далее сообщения будут извлекаться из очереди и передаваться для обработки конкретной оконной процедуре.

Для извлечения из очереди используется специальный цикл обработки сообщений (message loop), разрабатываемый для каждого приложения. В этом цикле сообщения извлекаются из очереди, определяется, какое окно (какая процедура обработки сообщений) должно это сообщение получить, при необходимости выполняются специальные действия, и только затем сообщение передается конкретной оконной процедуре. И такой процесс работает все время, пока работает приложение.

Процесс помещения сообщения в очередь и его извлечения из нее никак жестко не увязан по времени. Более того, может случиться так, что посланное сообщение вообще не будет обработано, например, если окно-получатель будет уничтожено прежде, чем успеет его обработать.

Рисунок 4. Обработка посланных сообщений в Windows

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

Этот процесс называется посылкой (post) сообщений, так как посылка сообщения напоминает посылку письма: посылающий сообщение указывает адресата, отправляет сообщение и больше о нем не беспокоится. Отправитель не знает, когда точно его сообщение получит адресат. Такой способ обработки сообщений часто называется асинхронным.

Извлечение сообщений из очереди приложения и направление их соответствующим окнам осуществляет цикл обработки сообщений, обычно входящий в функцию WinMain. Этот процесс выполняется в несколько приемов:

сообщение выбирается из очереди с помощью функции GetMessage или PeekMessage

затем сообщение транслируется с помощью функции TranslateMessage В некоторых руководствах в простейших примерах обходятся без трансляции вообще. Однако это является не совсем корректным, так как функция TranslateMessage распознает комбинацию клавиш Alt+Space как команду нажатия на кнопку системного меню. Конечно без нее приложение будет работать, но не в полной мере реализует стандартный клавиатурный интерфейс. (одно сообщение может порождать последовательность других или заменяться, как, например, происходит для сообщений клавиатуры WM_KEYDOWN). Часто трансляция состоит из вызова более чем одной функции, сюда могут добавляться специальные средства трансляции акселераторов и немодальных диалогов (об этом позже).

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

Эти функции образуют цикл обработки сообщений, так как после завершения обработки одного сообщения приложение должно приготовиться к обработке следующего. Цикл заканчивается только при завершении работы приложения.

MSG msg;

while ( GetMessage( &msg, NULL, NULL, NULL ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}

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

BOOL GetMessage( lpMsg, hWnd, uMsgFilterMin, uMsgFilterMax );

lpMsg указывает на структуру MSG, в которую будет записано полученное сообщение. Если очередь сообщений пуста, то GetMessage передает управление оболочке, так что та может начать обработку сообщений другого приложения.

Какие же данные передаются одним сообщением?

typedef struct tagMSG {
HWND hwnd; // хендл окна-получателя
UINT message; // номер сообщения WM_...
WPARAM wParam; // параметр сообщения
LPARAM lParam; // параметр сообщения
DWORD time; // время поступления сообщения
POINT pt; // координаты сообщения (для сообщений мыши)
} MSG;

Поле message структуры MSG задает номер сообщения, посланного системой. Интерпретация параметров сообщения wParam и lParam зависит от самого сообщения. Для этого надо смотреть описание конкретного сообщения и обрабатывать параметры соответствующим образом. Так как в системе определено огромное количество разных сообщений, то для простоты использования применяются символические имена сообщений, задаваемыми с помощью #define в заголовочном файле. В качестве примера можно привести сообщения WM_CREATE, WM_PAINT, WM_QUIT.

hWnd указывает хендл окна, сообщения для которого будут выбираться из очереди. Если hWnd равен NULL, то будут выбираться сообщения для всех окон данного приложения, а если hWnd указывает реальное окно, то из очереди будут выбираться все сообщения, направленные этому окну или его потомкам (дочерним или используемым окнами, или их потомкам, в том числе отдаленным).

uMsgFilterMin и uMsgFilterMax обычно установлены в NULL. Вообще они задают фильтр для сообщений. GetMessage выбирает из очереди сообщения, номера (имена) которых лежат в интервале от uMsgFilterMin до uMsgFilterMax. Нулевые значения исключают фильтрацию.

Функция GetMessage возвращает во всех случаях, кроме одного, ненулевое значение, указывающее, что цикл надо продолжать. Только в одном случае эта функция возвратит 0 -- если она извлечет из очереди сообщение WM_QUIT. Это сообщение посылается только при окончании работы приложения.

После завершения цикла надо сделать совсем немногое -- освободить память от тех объектов, которые создавались во время работы приложения (если они еще существуют). Некоторые объекты, которые уничтожаются автоматически, можно не освобождать -- это сделает Windows. Таков, например, зарегистрированный нами класс окон.

И остается еще одно дело: так как WinMain возвращает результат, то мы должны вернуть какое-либо значение. В Windows принято, что возвращаемое значение является параметром wParam сообщения WM_QUIT, завершившего цикл обработки сообщений. Таким образом мы пишем:

return msg.wParam;

Оконная процедура

Пока мы рассмотрели только функцию WinMain, причем она будет без существенных изменений сохраняться и в последующих примерах. Теперь мы должны написать оконную функцию. Строго говоря, описать ее лучше перед WinMain -- тогда не надо описывать ее прототип.

И еще одно замечание: после вызова функции RegisterClass, регистрирующей данную оконную процедуру, вы не должны вызывать ее напрямую -- это приведет к ошибке. Вызывать эту функцию может только Windows. Позже мы узнаем, почему это так и как можно ее вызвать самим.

Оконная функция должна быть декларирована следующим образом (в случае Win32 API ключевое слово _export может быть пропущено, подробнее об описании оконных функций см. в разделе, посвященном диспетчеру памяти):

LRESULT WINAPI _export proc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
// ...
}

В качестве аргументов мы получаем параметры переданного сообщения. Обычно оконные функции оформляются примерно по такой схеме:

LRESULT WINAPI _export proc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
// описание внутренних переменных

switch ( uMsg ) {
case WM_...:
// обработка нужного сообщения
break;

// обработка других сообщений...

default:
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
return 0L;
}

Главным элементом является конструкция switch, которая позволяет написать обработку каждого отдельного сообщения, полученного окном. В объектных библиотеках эти функции берет на себя базовый интерактивный объект, позволяющий связать определенные методы класса с получаемыми сообщениями.

Для упрощения написания оконной функции Windows предлагает специальную функцию

LRESULT DefWindowProc( hWnd, uMsg, wParam, lParam );

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

Сообщения, которые получает окно, информируют его о самых разных событиях, происходящих с этим окном, с приложением в целом, с самой системой и так далее. Сейчас мы рассмотрим четыре сообщения, которые применяются в рассмотренном примере, и их обработку.

Сообщение WM_CREATE

Самым первым мы рассмотрим сообщение WM_CREATE. Это сообщение посылается окну в тот момент, когда оно создается. Реальным созданием окна ведает функция CreateWindow, а не обработчик сообщения WM_CREATE. Вы в этот момент должны инициализировать свои переменные, выполнить необходимые настройки, создать требуемые объекты и прочее. При создании окно еще невидимо -- поэтому Вы можете менять его размеры, устанавливать в нужное положение, менять цвета не опасаясь мелькания на экране. Часто здесь создаются необходимые структуры и выделяются требуемые окном ресурсы.

Стандартная обработка этого сообщения необязательна -- функция DefWindowProc просто возвращает 0 в ответ на это сообщение.

Параметр wParam не используется, а параметр lParam содержит указатель В Windows все указатели, которые получает или передает Вам система являются 32х разрядными. В случае Windows API это будут дальние (far) указатели, а в случае Win32 это ближние (near), так как они уже являются 32х разрядными. на структуру CREATESTRUCT. В этой структуре передается основная информация о создаваемом окне.

typedef struct tagCREATESTRUCT {
void FAR* lpCreateParams; // указатель на дополнительные данные,
// переданный как параметр lpParam в вызове
// функции CreateWindow или CreateWindowEx
HINSTANCE hInstance; // хендл копии приложения, создавшей окно
HMENU hMenu; // хендл меню (или NULL, если нет)
HWND hwndParent; // хендл родительского окна (или NULL)
int cy, cx; // размеры окна
int y, x; // положение окна
LONG style; // стили окна
LPCSTR lpszName; // заголовок окна
LPCSTR lpszClass; // имя класса, к которому принадлежит окно
DWORD dwExStyle; // расширенные стили окна (см. CreateWindowEx)
} CREATESTRUCT;

Поля x, y, cx и cy в момент обработки сообщения WM_CREATE могут быть еще не определены. При необходимости получить информацию о размере или положении окна надо пользоваться функциями GetWindowRect или GetClientRect, которые возвращают корректный результат

Возвращаемое обработчиком значение:

не 0 -- возникла ошибка, окно надо уничтожить (далее, при уничтожении, будет получено сообщение WM_DESTROY), функция CreateWindow или CreateWindowEx вернет NULL.

Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13



© 2003-2013
Рефераты бесплатно, курсовые, рефераты биология, большая бибилиотека рефератов, дипломы, научные работы, рефераты право, рефераты, рефераты скачать, рефераты литература, курсовые работы, реферат, доклады, рефераты медицина, рефераты на тему, сочинения, реферат бесплатно, рефераты авиация, рефераты психология, рефераты математика, рефераты кулинария, рефераты логистика, рефераты анатомия, рефераты маркетинг, рефераты релиния, рефераты социология, рефераты менеджемент.