Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная 1.docx
Скачиваний:
1
Добавлен:
10.07.2019
Размер:
253.08 Кб
Скачать

ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ

специальность АСУ

ПРОГРАММИРОВАНИЕ ГРАФИЧЕСКИХ ИНТЕРФЕЙСОВ

в среде Microsoft Visual Studio C++

Лабораторная работа №1

Тема. Приложения Win32 API.

Цель. Получить начальные практические навыки программирования в Win32 API.

Основное содержание работы. Написать и отладить простую программу, как приложение Win32.

Краткие теоретические сведения

  • Создание нового проекта программы.

Для создания нового проект выполните следующие действия. В меню File выберите последовательно New и Project. В появившемся диалоговом окне New Project выберите тип проекта Visual C++/Win32 и шаблон Win32 Proect как показано на рисунке. В строке Name укажите имя проекта, в строке Lacation папку для проекта и отметьте Create directory for solution.

Нажав OK, мы запустим мастера генерации приложений.

Н ажмем Next. В окне мастера установим опцию Empty project (пустой проект).

Нажмем Finish. Мастер создаст пустой проект.

Т еперь надо добавить в проект файлы. Пока добавим один файл – lab1.cpp, в который и запишем нашу простейшую GUI-программу. Для этого щелкнем правой кнопкой мыши на имени проекта и выберем последовательно Add и New Item.

В появившемся окне выберем категорию Visual C++ и тип добавляемого в проект файла – C++ File(.cpp). В строке Name укажем имя файла и нажмем кнопку Add.

Файл добавится в проект. Пока он пустой. Аналогично можно добавлять в проект и другие файлы.

  • Просмотрщик решений Solution Explorer

Workspace Viewer по умолчанию расположен слева окна среды разработки и

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

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

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

  • Интерфейс прикладного программирования (API)

API(Application Programming Interface)-это набор функций, предоставляющих программисту возможность создавать программы(приложения) для Windows NT, Windows 95/98, Windows 2000 и т.д., т.е. для 32-разрядных платформ. Естественно, что эти платформы разнятся между собой, но набор функций, составляющих API, для них один и тот же. Все функции этого набора 32-битовые.

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

  • Программа для Windows

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

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

{

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

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

Пока не произошло необходимое для выхода событие

Выбрать из очереди сообщений очередное сообщение

Передать сообщение оконной функции

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

}

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

{

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

Возврат

}

  • Функция WinMain

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

1)создание класса окна приложения ;

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

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

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

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

int WINAPI WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

return 0;

}

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

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

Обратите внимание на слово WINAPI перед телом функции WinMain. Это слово указывает компилятору на необходимость сгенерировать перед выполнением этой функции специальный пролог и эпилог необходимый для функции, в которой запускается и завершается программа. Если это слово будет отсутствовать, то программа будет сгенерированна неправильно. Не забывайте включать это слово перед каждой функцией 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 своего программного модуля, приложение будет способно работать с файлами, выделять себе необходимую память, взаимодействовать с другими работающими программами, но будет неспособно организовать работу с пользователем. Для ее организации приложение должно создать свое окно, которое будет взаимодействовать с пользователем и получать от него команды.

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

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

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

  • Создание класса окна приложения

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

ATOM RegisterClass(const WNDCLASS *lpwc);

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

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

Прототип этой структуры такой.

typedef struct tagWNDCLASS

{ UINT style;

WNDPROC lpfnWndProc;

int cbClsExtra;

int cbWndExtra;

HINSTANCE hInstance;

HICON hIcon;

HCURSOR hCursor;

HBRUSH hbrBackground;

LPCWSTR lpszMenuName;

LPCWSTR lpszClassName;

} WNDCLASS;

Здесь:

style-стиль класса ;

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

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

cbWndExtra-число байт необходимых для хранения данных при создание каждого оконного объекта этого класса

hInstance-handle программного модуля ,который регистрирует класс;

hIcon- handle иконки;

hCursor- handle курсора;

hbrBackground-цвет фона окна;

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

lpszClassName-имя класса окна;

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

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

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

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

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

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

Обычно достаточно установить поле style равным CS_HREDRAW| CS_VREDRAW | CS_DBLCLKS.

lpfnWndProc- адрес функции обратного вызова для приема сообщений предназначенных для данного класса окна.

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

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

hIcon -handle иконки, которая будут появляться в правом верхнем углу главного окна приложения.

Загрузить необходимую иконку можно с помощью функций 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

);

где

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

uType -тип рисунка для копирования, укажем IMAGE_ICON

cxDesired- новая ширина иконки, укажем 16

cyDesired- новая высота иконки, укажем 16

fuFlags - флаги

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.

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

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

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

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

WNDCLASS w;

memset(&w,0,sizeof(WNDCLASS));

w.style = CS_HREDRAW | CS_VREDRAW;

w.lpfnWndProc = WndProc;

w.hInstance = hInstance;

w.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

w.lpszClassName = "MyClass";

w.hIcon = LoadIcon(NULL, IDI_APPLICATION);

w.hCursor =LoadCursor(NULL,IDC_IBEAM);

RegisterClass(&w);

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

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

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

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

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

LRESULT CALLBACK WndProc(

HWND hwnd, //хэндл оконного объекта

UINT uMsg, //код сообщения

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

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

);

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

Рассмотрим прототип функции более подробно.

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

Тип значения, возвращаемый функции класса окна LRESULT, определен как 32-битное значащее целое, но в зависимости от сообщения в uMsg, его, возможно, потребуется преобразовать к указателю на некоторое значения или к другому целому типу, смотрите описание соответствующего сообщения в документации. Это значение определяет результат обработки сообщения, поэтому оно всегда должно передаваться OC при завершение работы функции.

Рассмотрим параметры функции.

HWND hwnd- handle объекта окна, для которого предназначено сообщение, если создано несколько объектов данного оконного класса, то по этому handle функции обработчик выбирает нужный; для главного окна приложения, которое существует в одном экземпляре его можно проигнорировать.

UINT uMsg- код сообщения, беззнаковое целое.

WPARAM wParam и LPARAM lParam – 32-битное целые, в которые передаются параметры сообщения, их возможно потребуется преобразовать к указателям на некоторое значения или к другому целому типу.

Всего в Windows есть более 1000 сообщений, которые может получить любая функция класса окна, и все они должны быть обработаны. Однако вряд ли приложению понадобится обрабатывать их все; те сообщения, обрабатывать которые внутри функции класса окна нет необходимости, могут быть переданы OС для их обработки по умолчанию.

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

LRESULT DefWindowProc(

HWND hWnd, // хэндл окна

UINT Msg, // сообщение

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

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

);

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

Теперь мы можем написать простейшую функцию обработки сообщений.

LRESULT CALLBACK WndProc(

HWND hwnd, UINT message,

WPARAM wParam,

LPARAM lParam)

{

return DefWindowProc(hwnd,message,wParam,lParam)

}

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

Создание главного окна приложения

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

Создание любого объекта оконного типа, выполняется функцией CreateWindow.

HWND CreateWindow(

LPCTSTR lpClassName, //указатель на строку с именем класса окна

LPCTSTR lpWindowName, //указатель на строку с заголовком окна

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

int x, //x-координата левого верхнего угла окна

int y, //y-координата левого верхнего угла окна

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

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

HWND hWndParent, //handle родительского окна

HMENU hMenu, //handle меню

HANDLE hInstance, //handle того программного модуля, который создает окно

LPVOID lpParam //указатель на дополнительные параметры

);

Рассмотрим параметры окна более подробно.

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

lpWindowName-указатель на заголовок данного окна, если заголовок данного окна не нужет то пусть этот параметр будет NULL.

x ,y, nWidth, nHeight- координаты окна и его размеры.

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

hWndParent-handle родительского окна, для главного окна приложения созданного со стилем WS_OVERLAPPED должен быть равен NULL, для дочернего окна должен быть равен handle какого-нибудь из окон уже созданных данным приложением, для всплывающих окон или NULL или handle одного из уже определенных окон.

hMenu-handle объекта класса оконное меню или числовой идентификатор окна, который вы задали для дочернего окна. Если ваше гланое окно не имеет меню, то укажите этот параметр как NULL .

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

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

WS_POPUP- создает всплывающее окно, то есть способное появляться в любой части экрана при нажатии правой кнопки меню..

WS_CHILD- создает дочернее окно, это окно имеет следующие особенности:

1)при задание своего положения использует координаты, отсчитываемые от левого верхнего угла клиентской части окна родителя (то есть той части прямоугольника, занимаемого окном, которая не занята заголовком и рамкой)

2)если изменяется положение родительского окна, то дочерние окна также перемещаются вместе с ним, при этом их координаты относительно клиентской части главного окна сохраняются

3) при уничтожение родительского окна все дочерние окна уничтожаются вместе с ним

WS_CAPTION- создает окно, которое имеет заголовок, любое перекрывающееся окно создается с таким стилем автоматически

WS_BORDER- создает окно, которое имеет толстую рамку вокруг окна, любое перекрывающееся окно создается с таким стилем автоматически

WS_SIZEBOX- окно может изменять размер, если пользователь будет двигать рамку окна

WS_SYSMENU- окно имеет системное меню.

WS_MAXIMIZEBOX и WS_MINIMIZEBOX- окно имеет кнопки увеличения размера до максимального и уменьшения размера до минимального соответственно.

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

WS_OVERLAPPEDWINDOW- рекомендуемый стиль перекрывающегося окна для главного окна приложения, определен как битовая комбинация следующих стилей WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU,WS_THICKFRAME,WS_MINIMIZEBO, WS_MAXIMIZEBOX