Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Технологии программирования. Программирование графических интерфейс

.pdf
Скачиваний:
3
Добавлен:
15.11.2022
Размер:
2.24 Mб
Скачать

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

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

API (Application Programming Interface) – это набор функ-

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

Таким образом, Windows API есть не что иное, как просто набор функций, формирующих интерфейс между приложением и компьютером в целом.

1.5. Программа для Windows

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

WinMain (список аргументов)

{

Создание класса окна Создание экземпляра класса окна

Пока не произошло необходимое для выхода событие Выбрать из очереди сообщений очередное сообщение Передать сообщение оконной функции

11

Возврат из программы}

}

WindowsFunction(список аргументов)

{

Обработать полученное сообщение Возврат

}

Функция WinMain() является обязательным компонентом любого приложения и отвечает за следующее:

1)регистрацию класса окна приложения;

2)начальную инициализацию приложения;

3)создание и инициализацию цикла обработки сообщений;

4)завершение выполнения программы, обычно в результате получения сообщения WM_QUIT.

Рассмотрим простейшее приложение Win32.

int WINAPI WinMain(HINSTANCEh

Instance,

HINSTANCE

hPrevInstance,

LPSTR

lpCmdLine,

int

nCmdShow)

{

 

return 0;

 

}

Это приложение ничего заметного на глаз не делает и сразу же прекращает свою работу, возвращая управление OC с кодом возврата 0.

Первое заметное отличие этой программы от любой программы для DOS – это замена функции main () функцией WinMain(). Это вызвано тем, что параметры программы, которые приложение получает от операционной системы Windows, иные, чем для DOS, поэтому потребовалась иная функция, с которой запускается и в которой завершается программа.

Обратите внимание на слово WINAPI перед телом функции WinMain. Это слово указывает компилятору на необходимость сгенерировать перед выполнением этой функции специ-

12

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

Рассмотрим те параметры, которые получает приложение от OS в функции WinMain.

lpCmdLine – указатель на строку, содержащую командную строку программы, это параметры для программы, переданные пользователем, если таких параметров нет, то равна NULL. В целом схоже с аналогичной строкой параметров, которые программа получаетотпользователяDOS.

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

hInstance – handle программного модуля приложения. Среди классов Win32 ваша программа также является объектом класса HINSTANCE, желательно запомнить его handle в какойнибудь глобальной переменной, так как некоторые функции API могут потребовать его в качестве параметра. В основном он необходим при работе с ресурсами приложений, организации многозадачности и при создании оконных объектов.

Вы всегда можете получить его в своей программе с по-

мощью функции HINSTANCE GetModuleHandle (LPCTSTR lpModuleName), которая возвращает handle программного модуля, заданного по имени его .exe или .dll файла, или, если параметр LpModuleName равен NULL, то handle того программного модуля, из которого эта функция была вызвана.

hPrevInstance – параметр перешел в Win32 для совместимости с предыдущими версиями Win16; в Win32 не используется и всегда равен NULL.

Имея в своем распоряжение handle своего программного модуля, приложение будет способно работать с файлами, выде-

13

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

Сточки зрения пользователя, окно программы – это прямоугольная область экрана, где программа что-либо рисует и выполняет все необходимые действия для работы.

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

Любое созданное нами окно Windows будет принадлежать

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

1.6. Регистрация класса окна

Для регистрации класса окна рекомендуется использовать функцию RegisterClassEx().

ATOM RegisterClassEx( const WNDCLASSEX *lpwcx;

);

Здесь lpwcx – указатель на структуру, содержащую данные о регистрируемом классе окна.

14

Структура WNDCLASSEX определена только для

Win95/Win98/Win2000.

Для WidowsNT следует использовать структуру WNDCLASS

ифункциюRegisterClass(const WNDCLASS *lpwc).

При успехе функция возвращает уникальный целочисленный идентификатор (ATOM), целое число, которое уникально для каждого зарегистрированного класса окна, или 0 – в случае неудачи.

Параметром функции будет указатель на структуру WNDCLASSEX, в которой содержатся все необходимые данные о классе окна.

Прототип этой структуры такой: typedef struct _WNDCLASSEX {

UINT cbSize;

размерэтой структурыв байтах

UINT style;

стилькласса

WNDPROC lpfnWndProc; адрес функции окна для этого

 

класса

int cbClsExtra;

число байт, необходимых для хра-

 

ненияданныхдлякласса

int cbWndExtra;

число байт, необходимых для хра-

 

нения данных при создании каждо-

 

гооконногообъектаэтогокласса

HANDLE hInstance;

handle програмного модуля, кото-

 

рыйрегистрируеткласс

HICONhIcon;

handle большойиконки

HCURSORhCursor;

handle курсора

HBRUSHhbrBackground;

цвет кисти фона

LPCTSTRlpszMenuName; имя менюдля этого классаокна

LPCTSTRlpszClassName;

имя класса окна

HICONhIconSm;

handle маленькой иконки

} WNDCLASSEX;

Опишем части структуры более подробно.

cbSize – указывает размер этой структуры в байтах, используйте sizeof (WNDCLASSEX) для правильного заполнения этого поля.

15

cbClsExtra и cbWndExtra – размер областей памяти, которые выделит система для хранения дополнительных данных об окне после успешной регистрации класса окна и после успешного создания каждого оконного объекта этого класса. Мы не будем требовать у системы эту память, поэтому установим эти значения в ноль.

hInstance – handle программного модуля, который регистрирует окно заданного класса, используйте значение, переданное в параметрах функции WinMain.

hIcon и hIconSm – handle большой и маленькой иконки, которые будут появляться соответственно при нажатииAlt+Tab и в правом верхнем углу главного окна приложения.

Загрузить необходимую иконку можно с помощью функ-

ций LoadIcon или LoadImage.

Воспользуемся функцией LoadIcon для того, чтобы загрузить одну из встроенных в OC иконок.

HICON LoadIcon (HINSTANCE hInstance, LPCTSTR

lpIconName);

где hInstance – идентификатор программного модуля, из ресурсов которого необходимо загрузить иконку, для загрузки иконки из ресурсов OС укажите этот параметр как NULL.

lpIconName – имя иконки; для задания идентификатора одной из встроенных иконок в виде флажка Windows укажем этот параметр как IDI_APPLICATION.

Функция LoadIcon загружает только иконки размером 32*32,для загрузки иконки меньшего размера мы можем просто уменьшить размер загруженной иконки в 2 раза например, с помощью функции CopyImage, или загрузить иконку требуемого размера с помощью функции LoadImage.

ВоспользуемсяфункциейCopyImage.

HANDLE CopyImage(

HANDLE hImage,UINT uType, int cxDesired, int cyDesired, UINT fuFlags);

16

где hImage – handle уже загруженной иконки, загрузим ее с помощью функции LoadIcon.

uType – типрисункадлякопирования, укажемIMAGE_ICON. cxDesired – новая ширина иконки, укажем 16.

cyDesired – новая высота иконки, укажем 16. fuFlags – флаги.

Присвоим полю hIconSm значение, полученное от функции CopyImage, преобразовав его ктипу HICON.

hCursor – handle той формы курсора, которую он будет принимать, когда находится в оконном прямоугольнике, принадлежащем классу, заданному в lpszClassName.

Для ее загрузки воспользуемся функцией LoadCursor. HCURSOR LoadCursor(HINSTANCE hInstance,

LPCTSTR lpCursorName);

где hInstance – идентификатор программного модуля, из ресурсов которого необходимо загрузить рисунок курсора, для загрузки иконки из ресурсов OС укажите этот параметр как NULL.

lpCursorName – имя курсора; для задания идентификатора одного из встроенных курсоров в виде флажка Windows укажем этот параметр как IDC_ARROW.

hbrBackground – фоновая кисть для данного класса окна, то есть тот цвет, которым будет закрашена средствами OС та часть окна или все окно перед тем, как приложение сможет чтолибо там изобразить.

Воспользуемся кистью с цветом окна по умолчанию, при-

своив этому полю значение (HBRUSH)(COLOR_WINDOW+1).

Всего в системе есть около двадцати таких предопределенных цветов, доступных по своим константным номерам, полный их список можно просмотреть в «помощи» среды разработки. При использовании какого-либо из них обязательно прибавьте к номеру 1 и преобразуйте к типу HBRUSH.

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

17

lpszClassName – имя класса окна; в системе не может быть два класса окна с одинаковыми именами, поэтому это имя должно быть уникальным, задается указателем на строку символов, содержащую это имя.

style – специфицирует стиль класса окна, то есть те необходимые свойства в поведение окон данного класса, которые нужно знать операционной системе.

Стили окна – это битовые флаги, которые могут комбинироваться с помощью логической операции ИЛИ, всего их более 10, но для нас сейчас представляют интерес следующие стили:

CS_DBLCLKS – сообщение посылается при двойном щелчке мыши.

CS_HREDRAW – если пользователь изменил высоту данного окна, то посылается сообщение об его перерисовке.

CS_VREDRAW – если пользователь изменил высоту данного окна, то посылается сообщение об его перерисовке.

Обычно достаточно установить поле style, равным

CS_HREDRAW| CS_VREDRAW | CS_DBLCLKS. lpfnWndProc – адрес функции обратного вызова для прие-

ма сообщений, предназначенных для данного класса окна. Теперь, когда все поля структуры описаны (не забудьте

написать свою функцию обратного вызова для своего класса окна), зарегистрируйте свой класс окна с помощью функции RegisterClassEx. Функции вернет вам так называемый ATOM, или шестнадцатиразрядное целое число, по которому система будет различать ваш класс окна. Вам его не нужно запоминать, но стоит проанализировать на предмет неравенства этого значения нулю. Если возвращенное число равно нулю, то зарегистрировать класс окна не удалось.

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

18

Пример 1.1. Регистрацииклассаокна

ATOM MyRegisterClass(HINSTANCE hInstance) {WNDCLASSEXwcex;

wcex.cbSize

= sizeof(WNDCLASSEX);

wcex.style

= CS_HREDRAW|CSVREDRAW;

wcex.lpfnWndProc

= (WNDPROC)WndProc;

wcex.cbClsExtra

= 0;

wcex.cbWndExtra

= 0;

wcex.hInstance

= hInstance;

wcex.HIcon

= LoadIcon(hInstance,IDI_APPLICATION);

wcex.hCursor

= LoadCursor(NULL,IDC_ARROW);

wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL;

wcex.lpClassName

= szWindowClass;

wcex.hIconSm

=

LoadIcon(wcex.hInstance,IDI_APPLICATION); ATOM atom=::RegisterClassEx(&wcex);

if(atom) returnatom;

else //Если данная версия Windows не поддерживает расширенный класс //окна

{

 

WNDCLASS wc;

 

wc.style

= CS_HREDRAW|CSVREDRAW;

wc.lpfnWndProc

= (WNDPROC)WndProc;

wc.cbClsExtra

= 0;

wc.cbWndExtra

= 0;

wc.hInstance

= hInstance;

wc.HIcon

= LoadIcon(hInstance,IDI_APPLICATION);

wc.hCursor

= LoadCursor(NULL,IDC_ARROW);

wc.hbrBackground

= (HBRUSH)(COLOR_WINDOW+1);

wc.lpszMenuName

= NULL;

wcex.lpClassName

= szWindowClass;

return ::RegisterClass(&wc);

}}

19

1.7. Сообщения и функция обратного вызова

Все оконные объекты Windows могут взаимодействовать между собой и системой с помощью вызова функций OС (редко) и путем посылки сообщений (чаще всего).

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

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

При регистрации оконного классадля OС передается указатель на функции, удовлетворяющий следующему прототипу (имя функции может быть любое):

LRESULTCALLBACKWndProc(

HWNDhwnd,

хэндл оконного объекта

UINTuMsg,

код сообщения

WPARAMwParam,

первый параметр сообщения

LPARAMlParam

второй параметр сообщения

);

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

20