Лекция 2. Структура приложения Windows 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Лекция 2. Структура приложения Windows



1. Простейшее Windows-приложение "Hello, World!"

Приложение (программа 2.1), которое выводит на экран диалоговое окно, показанное на рис. 2.1, вполне можно считать аналогом классической программы "Hello, World!".

 

Рис. 2.1. Простейшее Windows-приложение "Hello, World!"

 

#include <windows.h>

 

int WINAPI WinMain(HINSTANCE d1, HINSTANCE d2, LPSTR d3, int d4)

{

MessageBox(NULL, "Hello, World!", "", MB_OK);

return 0;

}

Программа 2.1. Простейшее Windows-приложения "Hello, World!".

 

C точки зрения программирования у этого "приложения" довольно сложное поведение. Традиционная консольная версия "Hello, World!" выводит сообщение на экран и заканчивает работу. Windows-приложение после вывода сообщения продолжает работать. На экране присутствует диалоговое окно, которое можно переместить по экрану мышью. Мышью можно нажать кнопку OK для завершения работы приложения. Если нажать мышью кнопку OK, но не отпускать левую кнопку мыши, то на экране будет видна кнопка OK, нарисованная в нажатом состоянии. Если, не отпуская кнопку мыши, перемещать указатель то на кнопку OK, то вне ее, эта кнопка будет менять свой внешний вид. У окна приложения есть небольшое меню (с единственной командой Переместить), которое можно вызвать нажатием комбинации Alt+Пробел или щелчком правой кнопки на заголовке окна. Приложение можно завершить клавишей Enter, Escape или пробел.

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

 

Приложение с циклом обработки сообщений

В программе 2.1 практически вся функциональность приложения сосредоточена (и скрыта) внутри функции MessageBox. Для лучшего понимания структуры приложения сделаем реализацию поведения видимой, другими словами, создадим окно, которым будем управлять сами, а не доверять это функции MessageBox.

Окно новой версии hello.cpp показано на рис. 2.2. Теперь слова "Hello, World!" выводятся как надпись на кнопке, занимающей всю клиентскую область окна (они также появляются в строке заголовка окна).

 

Рис. 2.2. Приложение "Hello, World!" с собственным циклом обработки сообщений.

 

"Типичное" приложение Windows в процессе инициализации сначала регистрирует новый оконный класс для своего главного окна. Затем приложение создает свое главное окно. Сейчас пока не будем регистрировать новый оконный класс, а используем один из стандартных оконных классов, BUTTON ("Кнопка"). Поведение этого класса не позволит в точности повторить приложение из п.1. В данный момент это не важно, главное, что в приложении можно будет увидеть назначение цикла обработки сообщений (программа 2.2).

 

#include <windows.h>

 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE d2, LPSTR d3, int d4)

{

HWND hwnd;

hwnd = CreateWindow("BUTTON", "Hello, World!",

WS_VISIBLE | BS_CENTER, 100, 100, 100, 80,

NULL, NULL, hInstance, NULL);

MSG msg;

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

{

if (msg.message == WM_LBUTTONUP)

{

DestroyWindow(hwnd);

PostQuitMessage(0);

}

DispatchMessage(&msg);

}

return msg.wParam;

}

Программа 2.2. Приложение "Hello, World!" с циклом обработки сообщений.

 

В данном примере виден цикл обработки сообщений. После создания окна программа входит в цикл while, в котором выполняется вызов функции Windows API для получения очередного сообщения – GetMessage. Эта функция возвращает значение FALSE только при получении сообщения WM_QUIT о завершении приложения. В цикле обрабатывается единственное сообщение, WM_LBUTTONUP, об отпускании левой кнопки мыши. Функция DestroyWindow уничтожает окно приложения, а PostQuitMessage посылает приложению сообщение WM_QUIT. Поэтому при очередном вызове GetMessage цикл обработки сообщений завершится. Все сообщения, кроме WM_LBUTTONUP, передаются функции DispatchMessage.

Диспетчеризация с помощью функции DispatchMessage означает передачу сообщений в оконную процедуру, "по умолчанию" приписанную оконному классу BUTTON. Как и в случае функции MessageBox, содержание оконной процедуры "по умолчанию" скрыто, т.к. она является частью операционной системы.

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

Рассмотренный пример не продемонстрировал строение оконной процедуры. Поэтому еще раз усложним "Hello, World!", чтобы в этом приложении был виден и цикл обработки сообщений, и оконная процедура.

 

Приложение с циклом обработки сообщений и оконной процедурой

Новая версия hello.cpp (программа 2.3) регистрирует собственный оконный класс. Это делается частично для косметических улучшений (чтобы отказаться от неестественного применения класса BUTTON для вывода сообщения), но главным образом для того, чтобы установить собственную оконную процедуру.

 

Рис. 2.3. Версия приложения "Hello, World!" с собственным оконным классом.

 

#include <windows.h>

 

void DrawHello(HWND hwnd)

{

PAINTSTRUCT paintStruct;

HDC hDC = BeginPaint(hwnd, &paintStruct);

 

if (hDC!= NULL)

{

RECT clientRect;

GetClientRect(hwnd, &clientRect);

DPtoLP(hDC, (LPPOINT)&clientRect, 2);

DrawText(hDC, "Hello, World!", -1, &clientRect,

DT_CENTER | DT_VCENTER | DT_SINGLELINE);

EndPaint(hwnd, &paintStruct);

}

}

 

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg,

WPARAM wParam, LPARAM lParam)

{

switch(uMsg)

{

case WM_PAINT: DrawHello(hwnd); break;

case WM_DESTROY: PostQuitMessage(0); break;

default: return DefWindowProc(hwnd, uMsg, wParam, lParam);

}

return 0;

}

 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR d3, int nCmdShow)

{

if (hPrevInstance == NULL)

{

WNDCLASS wndClass;

memset(&wndClass, 0, sizeof(wndClass));

wndClass.style = CS_HREDRAW | CS_VREDRAW;

wndClass.lpfnWndProc = WndProc;

wndClass.hInstance = hInstance;

wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);

wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

wndClass.lpszClassName = "HELLO";

if (!RegisterClass(&wndClass))

return FALSE;

}

 

HWND hwnd;

hwnd = CreateWindow("HELLO", "HELLO", WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,

NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

 

MSG msg;

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

DispatchMessage(&msg);

 

return msg.wParam;

}

Программа 2.3. Приложение "Hello, World!" с собственным оконным классом.

 

Новая версия приложения содержит примерно 60 строк исходного текста. Но оно выглядит как "полноценное" Windows-приложение (рис. 2.3), у которого есть системное меню, окно которого можно перемещать, изменять размер, сворачивать и разворачивать, оно умеет перерисовывать себя, реагировать на команду меню Закрыть и на комбинацию клавиш Alt+F4.

Как и раньше, выполнение программы начинается с функции WinMain. Сначала приложение проверяет, есть ли уже запущенный экземпляр данного приложения. Если есть, то оконный класс повторно регистрировать не надо. Иначе выполняется регистрация оконного класса, свойства и поведение которого описываются с помощью структуры WNDCLASS. В переменную lpfnWndProc этой структуры помещается адрес оконной процедуры. В нашем примере это будет функция WndProc.

Далее, вызывается функция CreateWindow для создания окна. После вывода окна на экран WinMain входит в цикл обработки сообщений. Этот цикл завершится, когда GetMessage вернет FALSE в результате получения сообщения WM_QUIT.

Функция WndProc демонстрирует назначение и структуру оконной процедуры, которая не была видна в предыдущих версиях "Hello, World!". Типичная оконная процедура на языке Си состоит из большого оператора switch. В зависимости от полученного сообщения, из этого оператора вызываются различные функции для обработки конкретных сообщений. В нашем примере обрабатываются только два сообщения: WM_PAINT и WM_DESTROY.

Сообщение WM_PAINT требует от приложения частично или полностью перерисовать содержимое окна. Большинство приложений перерисовывают только те области окна, которые нуждаются в перерисовке. В нашем случае, для простоты, на каждое сообщение WM_PAINT всегда выполняется вывод всей строки "Hello, World!".

Сообщение WM_DESTROY поступает в результате действий пользователя, которые приводят к уничтожению окна приложения. В качестве реакции наше приложение вызывает функцию PostQuitMessage. Т.о. гарантируется, что функция GetMessage в WinMain получит сообщение WM_QUIT и главный цикл обработки сообщений завершится.

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

 



Поделиться:


Последнее изменение этой страницы: 2016-08-01; просмотров: 658; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.138.125.2 (0.018 с.)