Создание окон

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

HWND CreateWindow(

LPCTSTR lpClassName, //Указатель на имя класса

LPCTSTR lpWindowName, //Указатель на имя окна

DWORD dwStyle, //Стиль окна

int x, //Координата левого края окна

int У, //Координата верхнего края окна

int nWidth, //Ширина окна

int nHeight, //Высота окна

HWND hWndParent, //Дескриптор окна-родителя или

//окна-владельца

HMENU hMenu, //Дескриптор меню или идентификатор

//создаваемого дочернего окна

HANDLE hInstance, //Дескриптор приложения

LPVOID lpParam //Указатель на данные окна

);

Назначение аргументов вызова этой функции:

1. lpClassName указывает на имя зарегистрированного функцией RegisterClass или определенного операционной системой класса.

2. lpWindowName указывает на строку, содержащую имя создаваемого окна.

3. dwStyle задает стиль окна. Стиль окон будет отдельно рассмотрен ниже.

4. х – координата левого края окна в пикселях. Для перекрывающихся или временных окон х отсчитывают от левого края экрана, дочерних окон – от левого края рабочей области родительского окна. Если для перекрывающегося окна со стилем WS_VISIBLE в качестве х задать константу CW_USEDEFAULT, Windows устанавливает не обязательно нулевую позицию по умолчанию для левого верхнего угла окна и игнорирует координату y верхнего края окна. Для временного и дочернего окна такая позиция по умолчанию равна (0, 0).

5. y – координата верхнего края окна в пикселях. Для перекрывающихся и временных окон ее отсчитывают от верхнего края экрана, дочерних окон – от верхнего края рабочей области родительского окна.

6. nWidth – ширина окна в пикселях. Для перекрывающихся окон можно задать равной CW_USEDEFAULT. В этом случае система устанавливает ненулевые значения ширины и высоты по умолчанию и игнорирует заданную высоту nHeight окна. Ширина и высота временного и дочернего окна по умолчанию равны нулю.

7. hWndParent может указывать только на инициированное окно. Дескриптор окна-родителя обязательно указывают при создании дочернего окна. Дескриптор окна-владельца для временного окна указывать необязательно.

8. hMenu – дескриптор меню или идентификатор создаваемого дочернего окна.

Меню перекрывающегося или временного окна можно задать тремя способами:

1. в классе окон указывают имя меню, и все окна этого класса могут пользоваться этим меню;

2. имя меню указывают как аргумент функции CreateWindow, и создаваемое окно будет пользоваться этим меню, игнорируя меню класса;

3. меню создают в процессе или после создания окна.

В первом и третьем случаях аргумент hMenu равен NULL. Если создается дочернее окно, то аргументом hMenu задают идентификатор этого окна (целочисленную константу).

Перед созданием окна функция CreateWindow посылает код сообщения WM_CREATE функции создаваемого окна. Она затем обрабатывает возвращаемое функцией окна значение и создает окно, если это значение равно 0, или не создает окна, если значение равно -1. Соответственно функция CreateWindow возвращает дескриптор созданного окна или NULL.

Стиль окна задает внешнее поведение окна.

Для описания стиля окна используют символические константы с префиксом WS_ (табл. 1.5).

По совокупности свойств различают перекрывающиеся (overlapped), временные (pop-up) и дочерние (child) окна.

Перекрывающиеся окна чаще используют в качестве окон приложения. Они всегда имеют заголовок (title bar), рамку и рабочую область окна (client region), могут иметь системное меню, кнопки восстановления размеров, закрытия и сворачивания окна в пиктограмму, горизонтальную и вертикальную полосы просмотра (scroll bar), меню, панель инструментов (tool bar) и строку состояния (status bar) (см. рис. 1.1). Базовый стиль таких окон описан константой WS_OVERLAPPED. Чаще используемый стиль окон WS_OVERLAPPEDWINDOW вдобавок к базовому указывает, что окно имеет системное меню, кнопки восстановления размеров, закрытия и сворачивания окна.

Перекрывающееся окно может принадлежать другому окну (владельцу). Если окно-владелец сворачивается в пиктограмму, то подчиненные ему окна становятся невидимыми. При уничтожении окна автоматически уничтожаются подчиненные ему окна. Подчиненные окна всегда располагаются над поверхностью окна-владельца, загораживая его.

Временные окна обычно используют для вывода сообщений пользователю и остаются на экране непродолжительное время. Базовый стиль временного окна описан константой WS_POPUP. Такое окно по умолчанию не имеет заголовка. Чаще временное окно описывают константой WS_POPUPWINDOW. Для добавления к временному окну системного меню и заголовка стиль WS_POPUPWINDOW комбинируют со стилем WS_CAPTION. Во всем остальном временные окна – это специальный вид перекрывающихся окон.

Дочерние окна используют для создания органов управления. Определяемые системой классы органов управления (кнопки, полосы просмотра и т.п.) представляют собой дочерние окна. Базовый стиль дочерних окон описан константой WS_CHILD. Этот стиль полностью совпадает со стилем WS_CHILDWINDOW. Дочерние окна не имеют кнопок минимизации и максимального увеличения размера, но всегда имеют окно-родителя. Они "прилипают" к поверхности родителя, перемещаются с ним и не могут выйти за пределы родительского окна.

4. Главная функция приложения

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

Пример описания функции WinMain:

int WINAPI WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpszCmdLine,

int nCmdShow)

{

MSG msg;

HWND hwnd;

if (!RegClass(WndProc, szClassName))

return FALSE;

hwnd = CreateWindow(szClassName, "Пример 1",

WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, 0, 0, hInstance,NULL);

if (!hwnd) return FALSE;

ShowWindow(hwnd, SW_SHOWMAXIMIZED);

UpdateWindow(hwnd);

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

{ TranslateMessage(&msg); DispatchMessage(&msg); }

return msg.wParam;

}

Имя, тип возврата и список формальных параметров функции определены требованиями Windows API. Модификатор WINAPI указывает на то, что функция при получении аргументов сама должна откорректировать порядок расположения аргументов в стеке.

Параметр hInstance от операционной системы получает дескриптор текущего экземпляра приложения. Параметр hPrevInstance в 16-разрядных приложениях указывает на активный предыдущий экземпляр приложения или NULL. В приложениях Win32 он всегда равен NULL и по нему невозможно узнать о существовании других активных экземпляров этого приложения. Параметр lpszCmdLine указывает на строку с аргументами командной строки запуска приложения. При обычном запуске этот параметр равен NULL. Параметр nCmdShow передает приложению способ начального отображения окна.

В теле функции WinMain описаны переменные msg и hwnd. Переменная msg предназначена для временного хранения сообщений при их получении и распределении. Переменная hwnd хранит дескриптор созданного окна.

Сообщение msg представляет собой структуру типа MSG:

typedef struct

{

HWND hwnd; //Дескриптор окна-адресата

UINT message; //Код сообщения

WPARAM wParam; //Содержимое сообщения

LPARAM lParam; //Содержимое сообщения

DWORD time; //Время отправления

POINT pt; //Координаты места отправления

} MSG; //Имя типа

Для регистрации класса окон вызывают функцию RegClass:

if (!RegClass(WndProc, szClassName)) return FALSE;

Для создания окна вызвана функция CreateWindow. Если окно не создано, приложение завершает свою работу.

Следующий после создания окна шаг выполняют не всегда. В данном примере окно не имеет стиля WS_VISIBLE и создано только в памяти. Для отображения окна вызывают функцию ShowWindow:

ShowWindow(hwnd, SW_SHOWMAXIMIZED);

Эта функция переводит окно hwnd в состояние, определяемое вторым параметром. Здесь окно hwnd отображают в максимально распахнутом виде.

Следующая функция сообщает функции окна hwnd о необходимости "перерисовки" рабочей области:

UpdateWindow(hwnd);

Далее следует цикл, который называется циклом обработки сообщений:

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

{ TranslateMessage(&msg); DispatchMessage(&msg); }

Здесь функция GetMessage выбирает сообщение из очереди сообщений приложения, TranslateMessage транслирует клавиатурные сообщения, DispatchMessage распределяет сообщения по функциям окон. Именно здесь происходит "вызов" функции окна.

Рассмотрим прототипы вышеперечисленных функций.

Функция ShowWindow объявлена следующим образом:

BOOL ShowWindow(HWND hwnd, int nCmdShow);

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

Константа Действие функции ShowWindow  
SW_HIDE Скрывает окно hwnd и активизирует другое окно  
SW_MAXIMIZE Максимизирует окно  
SW_MINIMIZE Сворачивает окно hwnd и активизирует расположенное под ним окно  
SW_RESTORE Восстанавливает свернутое окно hwnd
SW_SHOW Активизирует окно hwnd в текущих размерах и позиции
SW_SHOWMAXIMIZED Активизирует окно hwnd в максимально распахнутом виде
SW_SHOWMINIMIZED Активизирует окно hwnd в свернутом виде
SW_SHOWMINNOACTIVE Сворачивает окно hwnd
SW_SHOWNA Показывает состояние окна hwnd
SW_SHOWNOACTIVATE Показывает окно hwnd в текущих координатах
SW_SHOWNORMAL Активизирует и отображает окно hwnd в первоначальных размерах и позиции

Функция GetMessage имеет следующий прототип:

BOOL GetMessage(LPMSG lpmsg, HWND hwnd,

WORD uMsgFilterMin, WORD uMsgFilterMax);

Параметр lpmsg указывает на структуру типа MSG, в которую будет записано выбираемое сообщение, hwnd – дескриптор окна, для которого нужно выбрать сообщение. Если hwnd = NULL, то выбираются сообщения для всех окон приложения. Параметры uMsgFilterMin и uMsgFilterMax указывают диапазон выбираемых сообщений, задавая соответственно минимальное и максимальное значение кодов сообщений. Если для этих параметров указать нулевые значения, из очереди будут выбираться все сообщения.

Функция GetMessage выбранное сообщение удаляет из очереди и записывает его в структуру, адрес которой задан ее первым параметром. При выборке сообщения с кодом WM_QUIT она возвращает 0, и завершается цикл обработки сообщений. При выборке других сообщений функция GetMessage возвращает ненулевое значение.

После этого функция WinMain возвращает управление и значение поля wParam последнего сообщения операционной системе.

5. Создание приложения Win32

Структура текста приложения определяется двумя требованиями:

1. Текст содержит описание функции с именем WinMain.

2. Если регистрируются новые классы, то текст содержит описание структуры типа WNDCLASS и функций окон этих классов.

Рассмотрим пошагово процесс создания базового приложения на базе Win32, отображающего в окне надпись "Hello, World!".

1. В меню File последовательно выберите пункты New и Project.

2. В левой области диалогового окна New Project щелкните Installed Templates (Установленные шаблоны), выберите Visual C++ и щелкните Win32. В средней области выберите Win32 Project.

3. В поле Name введите имя проекта, например UP0101_fio (UP – учебная практика, 01 – первый день, 01 – первое приложение, fio – ваши инициалы).

4. В поле Location (Расположение) установите путь к вашим проектам (предположительно: c:\stud\5xx\, где хх – номер вашей группы).

5. В поле Solution name (Имя решения) укажите UP01_fio, чтобы все проекты первого дня практики сохранялись в одной папке.

6. Еще раз проверьте правильность ввода имени проекта и пути для сохранения и нажмите ОК.

7. На начальной странице Win32 Application Wizard (Мастер приложений Win32) ознакомьтесь с информацией и нажмите кнопку Next.

8. На странице Application Settings (Параметры приложения) в разделе Application type (Тип приложения) выберите Windows application (Приложение Windows).

9. В поле Additional options (Дополнительные параметры) выберите Empty project (Пустой проект).

10. Чтобы создать проект, нажмите кнопку Finish (Готово).

11. В окне Solution Explorer (Обозреватель решений) щелкните правой кнопкой мыши созданный проект UP0101_fio, выберите команду Add (Добавить) и щелкните New Item (Новый элемент).

12. В диалоговом окне Add New Item (Добавление нового элемента) выберите C++ File (.cpp).

13. В поле Name введите имя файла, например zad01_fio.cpp.

14. Нажмите кнопку Add.

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

#include <windows.h>

16. Добавьте функцию WinMain следующего синтаксиса:

//Описание главной функции

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)

{

return 0;

}

17. Добавьте функцию оконной процедуры с именем WndProc:

//Описание функции окон

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

{

return 0;

}

18. Добавьте глобальные переменные – дескриптор текущего приложения hInst и название класса окна szClassName: (fio – это ваши ФИО)

//Описание глобальных переменных

HINSTANCE hInstance;

TCHAR szClassName[]=TEXT("WinAppClass_fio");

19. В функции WinMain задайте значение глобальной переменной hInstance, установив его равным первому параметру, переданному в функцию WinMain:

hInstance = hInst;

20. Создайте функцию регистрации окна RegClass, пример которой с подробным описанием всех строк приведен в п. 2.2

//Описание функции регистрации классов

BOOL RegClass(WNDPROC Proc, LPCTSTR szName, UINT brBackground)

{

WNDCLASS wc;

wc.style = wc.cbClsExtra = wc.cbWndExtra = 0;

wc.lpfnWndProc = Proc;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(brBackground + 1);

wc.lpszMenuName = NULL;

wc.lpszClassName = szName;

return (RegisterClass(&wc)!= 0);

}

21. Добавьте в функцию WinMain вызов функции регистрации окна. Первым параметром передайте название функции окна, вторым параметром – имя регистрируемого класса окна, третьим – цвет окна. В случае неудачи будет показано стандартное окно сообщений (отредактируйте выдаваемые сообщения по своему вкусу!!!):

if (!RegClass(WndProc, szClassName, COLOR_WINDOW))

{

MessageBox(NULL,

TEXT("Вызов функции RegClass закончился с ошибкой!"),

TEXT("Первое Win32 приложение Иванова Ивана"),

NULL);

return FALSE;

}

22. Теперь можно создать окно. Для этого в функции WinMain воспользуйтесь функцией CreateWindow (отредактируйте заголовок окна!!!). Эта функция возвращает объект HWND, являющийся дескриптором окна:

HWND hwnd;

hwnd = CreateWindow(szClassName,

TEXT("Первое Win32 приложение Иванова Ивана"),

WS_OVERLAPPEDWINDOW | WS_VISIBLE,

CW_USEDEFAULT,

CW_USEDEFAULT,

CW_USEDEFAULT,

CW_USEDEFAULT,

0, 0,

hInstance,

NULL);

if (!hwnd)

{

MessageBox(NULL,

TEXT("Вызов функции CreateWindow завершился ошибкой!"),

TEXT("Первое Win32 приложение Иванова Ивана"),

NULL);

return FALSE;

}

23. Отредактируйте функцию окна WndProc, чтобы окно могло обрабатывать необходимые сообщения. Для минимальной функциональности окно должно обрабатывать сообщение WM_DESTROY, получаемое перед разрушением окна:

//Описание функции окон

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

{

switch (msg)

{

case WM_DESTROY: { PostQuitMessage(0); return 0;}

}

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

}

24. Теперь добавьте в функцию WinMain цикл обработки сообщений для прослушивания отправляемых ОС сообщений. Цикл обработки сообщений напоминает следующий код.

MSG msg;

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

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return (int) msg.wParam;

25. На данном этапе можно попробовать запустить приложение. Если все было выполнено правильно, то вы увидите окно, показанное на рисунке 1.2.

Рис. 1.2. Результат выполнения приложения

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

Как видно из листингов, приложение является обычной программой языка Си. Текст содержит привычные директивы, объявления и описания. Отличие содержится в заголовке главной функции, в специфической функции окна и в способе ее вызова.

Рассмотрим алгоритм работы этого приложения.

1. Классы окон регистрируют в начале работы приложения.

2. Окно приложения создают до передачи управления циклу обработки сообщений.

3. Отсутствуют вызовы функций ShowWindow и UpdateWindow. Это обусловлено тем, что окно создано со стилем WS_VISIBLE. В таком случае функция CreateWindow посылает все сообщения, которые необходимы для отображения созданного окна и перерисовки его рабочей области.

4. Управление передают циклу обработки сообщений. В теле этого цикла выбираются и распределяются сообщения.

5. Функция окна обрабатывает сообщение WM_DESTROY, а остальные сообщения возвращает системе. Функция окна приложения должна обрабатывать это сообщение.

6. Приложение завершает работу.

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

Может показаться, что отображение и удаление окна – слишком простая задача для такого "сложного" текста.

Проанализируем, что же на самом деле может сделать это приложение.

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

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

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


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: