СОЗДАНИЕ ОКНА
Полноценная программа для Win32 должна содержать как минимум две функции:
Win Main – главная функция, в которой создается основное окно программы и запускается цикл обработки сообщений;
WndProc – оконная процедура, в которой обрабатываются сообщения для основного окна программы.
Каркас Windows-программы
WinMain(список аргументов)
{
Подготовить и зарегистрировать класс окна;
Создать экземпляр окна зарегистрированного класса;
Пока не произошло необходимое для выхода событие
{
Извлечь очередное сообщение из очереди;
Передать его через Windows оконной функции;
}
Возврат из программы;
}
WndProc(список аргументов)
{
Обработать полученное сообщение;
Возврат;
}
Архитектура управления событиями
С внешним миром и операционной системой (ОС) приложение взаимодействует при помощи сообщений. Для приложения сообщение является уведомлением о том, что произошло некоторое событие. Это событие может требовать, а может и не требовать от приложения определенных действий. Инициируют события пользователи (щелчок мышкой, перемещение курсора и т.п.), само приложение, ОС.
Сообщение – это структура, содержащая следующие элементы:
– декскриптор окна, которому адресовано сообщение;
– код (номер) сообщения;
– дополнительную информацию, зависящую от кода сообщения.
Windows является многозадачной ОС. Сообщения от внешних источников в каждый конкретный момент времени адресуются только одному окну – активному.
Чтобы осуществлять диспетчеризацию сообщений ОС при своей загрузке создает в памяти глобальный объект, который называется системной очередью сообщений. Все сообщения помещаются в эту очередь. Windows периодически опрашивает эту очередь и посылает сообщение нужному окну, которое определяется при помощи дескриптора.
При загрузке приложения создается еще один глобальный объект, который называется очередью сообщений приложения.
Путь следования сообщений:
Событие > Системная очередь сообщений > Очередь сообщений приложения.
Оконная процедура
Оконная процедура – это функция обратного вызова, предназначенная для обработки сообщений, адресованных любому окну того «оконного класса», в котором содержится ссылка на данную процедуру.
Функция обратного вызова. Так называют функцию, которую вызывает сама ОС. Компилятор узнает функцию обратного вызова по спецификатору CALLBACK.
LRESULT CALLBACK Имя функции (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
LRESULT – тип возвращаемого значения;
hWnd – дескриптор окна;
uMsg – код сообщения;
wParam и lParam – параметры сообщения.
Каждый код сообщения – это уникальный символический идентификатор. Чаще всего приложение обрабатывает оконные сообщения, начинающиеся с префикса WM_. Сообщения от других элементов управления начинаются с префиксов:
BM_ – кнопки;
EM_ – текстовые поля;
LB_ – списки.
Оконный класс
Оконный класс (или класс окна) – это структура, определяющая основные характеристики окна, такие как стиль окна и ресурсы (пиктограмма, курсор, меню и кисть для закрашивания фона).
Кроме того, одно из полей структуры содержит адрес оконной процедуры, предназначенной для обработки сообщений.
Ссылка на оконный класс передается функции создания окна CreatWindow.
Использование класса окна позволяет создавать множество окон на основе одного и того же оконного класса. Например, все кнопки создаются на основе класса BUTTON. Аналогичные системные классы имеются и для других элементов управления, таких как, например, списки и поля редактирования. Все эти классы называются предопределенными или стандартными оконными классами.
Для главного окна приложения создается собственный класс, учитывающий индивидуальные требования к программе.
Цикл обработки сообщений
Все сообщения, адресованные приложению, Windows записывает в очередь сообщений приложения. Извлекает сообщение из очереди функция GetMessage. Если очередное сообщение WM_QUIT, то выход из цикла и приложение завершает свою работу. Если не WM_QUIT, то сообщение передается функции DispatchMessage, которая возвращает сообщение обратно в Windows. Windows отправляет сообщение для его обработки соответствующей оконной процедуре, иными словами Windows вызывает соответствующую оконную процедуру. После возврата из оконной процедуры Windows передает управление оператору, который расположен после DispatchMessage.
Файл исходного текста программы
Идентификаторы, такие как CS_HREDRAW, IDI_APPLICATION, IDC_ARROW, WS_SYSMENU, CW_USEDEFAULT, это просто числовые константы. Префикс обозначает основную категорию, к которой принадлежит константа.
Префикс |
Категория |
CS_ |
Опция стиля класса |
CW_ |
Опция создания класса |
DT_ |
Опция рисования текста |
IDC_ |
Идентификатор предопределенного курсора |
IDI_ |
Идентификатор предопределенной иконки (пиктограммы) |
WM_ |
Сообщение окна |
WS_ |
Стиль окна |
Регистрация класса окна
Сразу же после входа в функцию создается и регистрируется класс главного окна. Для этого необходимо заполнить структуру типа WNDCLASSEX, а затем передать адрес этой структуры в виде аргумента функции RegisterClassEx. Структура имеет 12 полей.
UINT cbSize – размер структуры в байтах. Значение поля д.б. равно длине структуры WNDCLASSEX;
UINT style – стиль класса окна. Стили перечислены в таблице.
Стиль |
Описание |
CS_GLOBALCLASS |
Создать класс, доступный всем приложениям. Обычно этот стиль применяется для создания определенных пользователем элементов управления в DLL |
CS_HREDRAW |
Перерисовать все окно, если изменен размер по горизонтали |
CS_NOCLOSE |
Запретить команду Close в системном меню |
CS_OWNDC |
Выделить уникальный контекст устройства для каждого окна, созданного при помощи этого класса |
CS_VREDRAW |
Перерисовать все окно, если изменен размер по вертикали |
WNDPROC lpfnWndProc – указатель на функцию окна (оконную процедуру).
int cbClsExtra – число дополнительных байтов, которые д.б. распределены в конце структуры класса. Поле используется редко.
int cbWndExtra – число дополнительных байтов, которые д.б. распределены вслед за экземпляром окна. Поле используется редко.
HINSTANSE hInstance – дескриптор экземпляра приложения, в котором находится оконная процедура для этого класса.
HICON hIcon – дескриптор пиктограммы.
HKURSOR hCursor – дескриптор курсора.
HBRUSH hbrBackground – дескриптор кисти.
LPCTSTR lpszMenuName – указатель на строку, содержащую имя меню. Если программа не имеет меню, то поле устанавливается в NULL.
LPCTSTR lpszClassName – указатель на строку, содержащую имя класса окна;
HICON hIconSm – дескриптор малой пиктограммы.
Создание окна
Если регистрация прошла успешно, то следующий этап – создание окна.
HWND CreateWindow (
LPCTSTR szWindowClass, имя зарегистрированного класса. Таким именем может быть либо имя класса, зарегистрированного при помощи функции RegisterClassEx, либо имя одного из предопределенных классов, перечисленных в таблице.
Класс |
Описание |
Префикс |
BUTTON |
Прямоугольное окно кнопки, группы, флажка, переключателя или пиктограммы |
BS_ |
COMBOBOX |
Элемент управления, объединяющий элементы элементы LISTBOX и EDIT. В поле редактирования отображается выбранная строка из LISTBOX |
CBS_ |
EDIT |
Прямоугольное окно, предназначенное для ввода текста |
ES_ |
LISTBOX |
Прямоугольное окно со списком строк, из которого можно выбрать любую строку |
LBS_ |
MDICLIENT |
Клиентское окно многодокументного интерфейса. Это окно получает сообщения, которые уп- равляют дочерними окнами в MDI-приложении |
|
RICHEDIT |
Элемент управления в дополнение к возможностям элемента EDIT. Позволяет редактировать текст с разными шрифтами и стилями |
ES_ |
RICHEDIT_CLASS |
Усовершенствованная версия RICHEDIT с дополни- тельными возможностями |
ES_ |
SCROLLBAR |
Элемент управления линейной прокрутки |
SBS_ |
STATIC |
Элемент управления статическим текстом. Применяется для размещения в окне текста или рамок |
SS_ |
LPCTSTR szTitle, указатель на строку, содержащую имя окна;
DWORD dwStyle, стиль окна, состоящий из значений, указанных в таблице
Обозначение стиля |
Описание |
WS_BORDER |
Создать окно с рамкой в виде тонкой линии |
WS_CAPTION |
Создать окно, которое имеет область заголовка (включает стиль WS_BORDER) |
WS_CHILD |
Создать дочернее окно. Окно не может иметь полосу меню и не может иметь стиль WS_POPUP |
WS_CLIPCHILDREN |
Исключить перерисовку дочерних окон, принадлежащих данному родительскому окну |
WS_CLIPSIBLINGS |
Исключить перерисовку соседних дочерних окон, при перерисовке данного дочернего окна |
WS_DLGFRAME |
Создать окно, имеющее рамку со стилем, типичным для диалоговых окон. Окно этого стиля не может иметь область заголовка |
WS_GROUP |
Считать данное окно первым в группе элементов управления (обычно группируются переключатели) |
WS_HSCROLL |
Создать окно с горизонтальной линейкой прокрутки |
WS_MAXIMIZE |
Создать окно, которое первоначально является развернутым |
WS_MAXIMIZEBOX |
Создать окно с кнопкой развертывания |
WS_MINIMIZE |
Создать окно, которое первоначально является свернутым |
WS_MINIMIZEBOX |
Создать окно с кнопкой свертывания |
WS_OVERLAPPED |
Создать перекрывающееся окно. Окно этого стиля имеет область заголовка и рамку |
WS_ OVERLAPPED |
Сочетание стилей WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MAXIMIZEBOX и WS_MAXIMIZEBOX |
WS_POPUP |
Создать всплывающее окно. Этот стиль не может использоваться совместно со стилем WS_CHILD |
WS_ POPUPWINDOW |
Сочетание стилей WS_BORDER, WS_POPUP и WS_SYSMENU. Чтобы сделать системное меню видимым, необходимо добавить стиль WS_CAPTION |
WS_SYSMENU |
Создать окно с системным меню в области заголовка |
WS_TABSTOP |
Стиль указывает, что на окне может остановиться фокус ввода, перемещзаемый при помощи клавиши TAB |
WS_THICKFRAME |
Создать окно с рамкой, которая позволяет изменять его размеры |
WS_VISIBLE |
Создать окно, которое сразу же является видимым |
WS_VSCROLL |
Создать окно с вертикальной линейкой прокрутки |
int x, горизонтальная позиция левого верхнего угла;
int y, вертикальная позиция левого верхнего угла;
Позиции x и y определяются в экранных координатах. Если позиция x не важна, то можно установить значение CW_USEDEFAULT. В этом случае Windows использует значение x и y по умолчанию. Если параметр x имеет значение CW_USEDEFAULT, то значение параметра y игнорируется.
int nWidth, ширина окна в пикселах;
int nHeight, высота окна в пикселах;
HWND hWndParent, дескриптор родительского окна. Если родительское окно отсутствует, то значение NULL.
HMENU hMenu, дескриптор меню окна или идентификатор элемента управления. Если используется меню, определенное в классе окна (поле lpszMenuName в структуре WNDCLASSEX) то присваивается NULL.
HINSTANCE hInstance, дескриптор экземпляра приложения.
LPVOID lParam указатель на данные, передаваемые в сообщении WM_CREATE. При необходимости он может быть использован в качестве указателя на дополнительные данные, передаваемые окну в момент его создания;
);
Функция создания окна возвращает дескриптор созданного окна (тип HWND).
Отображение окна на экране
Для отображения окна вызывается функция ShowWindow.
Прототип: ShowWindow(HWND hWnd, int nCmdShow).
HWND hWnd – дескриптор окна;
int nCmdShow – параметр определяет в каком виде будет показано окно. При начальном отображении главного окна рекомендуется присваивать этому параметру то значение, которое передается приложению через параметр nCmdShow функции WinMain. При последующих отображениях можно использовать любое из значений, приведенных в таблице.
Значение |
Описание |
SW_HIDE |
Скрыть окно |
SW_MAXIMIZE |
Развернуть окно |
SW_MINIMIZE |
Свернуть окно |
SW_SHOW |
Активизировать окно и показать в его текущих размерах и позиции |
SW_SHOWMINNOACTIVE |
Окно не выводится, а на панели задач появляются его имя и пиктограмма |
Обработка сообщений
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Переменная msg – это структура типа MSG, которая определена в заголовочных файлах Windows следующим образом:
typedef struct tagMSG {
HWND hwnd; // декскриптор окна, которому адресовано сообщ.
UINT message; // номер (идентификатор) сообщения (от 0 до 1024)
WPARAM wParam; // параметр сообщения wParam
LPARAM lParam; // параметр сообщения lParam
DWORD time; // время отправки сообщения
POINT pt; // поз. курс. (в экр. коорд.) в момент отправки сообщ.
} MSG;
Интерпретация параметров wParam и lParam зависит от номера сообщения.
Тип данных POINT:
typedef struct tagPoint {
LONG x;
LONG y;
} POINT;
Извлечение очередного сообщения осуществляется с помощью функции
GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax), где
lpMsg – задает адрес структуры типа MSG;
hWnd – дескриптор окна, принимающего сообщение. Обычно значение этого параметра равно NULL, что позволяет выбрать сообщения для любого окна приложения;
wMsgFilterMin – указывает минимальный номер принимаемого сообщения. Обычно равен нулю;
wMsgFilterMax – задает максимальный номер принимаемого сообщения. Также обычно равен нулю.
Функция GetMessage возвращает TRUE при извлечении любого сообщения, кроме WM_QUIT (выход из цикла и приложение завершает работу).
Вызов функции TranslateMessage нужен только в приложениях, которые должны обрабатывать ввод данных с клавиатуры. Сначала система генерирует сообщения о виртуальных клавишах, например: сообщение WM_KEYDOWN – когда клавиша наживается, и сообщение WM_KEYUP – когда клавиша отпускается. В сообщении WM_KEYDOWN содержится также информация о скан-коде (код, идентифицирующий нажатую клавишу и зависящий от аппаратной платформы).
Функция TranslateMessage преобразует сообщения WM_KEYDOWN и WM_KEYUP в сообщение WM_CHAR, которое содержит код символа (wParam) в виде значения TCHAR. Сообщение WM_CHAR помещается в очередь, а на следующей интерпретации цикла функция GetMessage извлекает его для последующей обработки.
Функция DispatchMessage передает структуру MSG обратно в Windows. Windows отправляет сообщение для его обработки соответствующей оконной процедуре, вызывая ее как функцию обратного вызова.
Оконная процедура
Реальная работа приложения осуществляется в оконной процедуре (в нашем конкретном случае WndProc).
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam):
Четыре параметра идентичны первым четырем полям структуры MSG.
Обычно используется оператор switch для определения сообщения. Если сообщение обрабатывается, то оконная процедура обязана вернуть нулевое значение. Все необрабатываемые оконной процедурой сообщения передаются системной функции DefWindowProc и возвращается значение, которое возвращает функция DefWindowProc. Программист пишет код только для тех сообщений, которые нуждаются в нестандартной обработке.