Я да. Лабораторная работа 1_1п. Лабораторная работа основы создания графических приложений в системе windows
Скачать 1.15 Mb.
|
Лабораторная работа 1. ОСНОВЫ СОЗДАНИЯ ГРАФИЧЕСКИХ ПРИЛОЖЕНИЙ В СИСТЕМЕ WINDOWS Цель работы. Изучение технологии создания программы для Windows с помощью прикладного интерфейса программирования Windows API Операционная система Windows является многозадачной операционной системой, что позволяет пользователю работать с несколькими одновременно запущенными приложениями. Для вывода информации, а также для получения информации от пользователя приложения используют окна. В системе Windows окном называется прямоугольная область экрана, которую приложение использует для вывода информации и получения данных от пользователя. Каждое окно приложения совместно использует экран с окнами других приложений. В один момент времени лишь одно окно может получать данные, вводимые пользователем. Такое окно называется активным. С помощью мыши, клавиатуры и других устройств пользователь может взаимодействовать с окном и создавшим его приложением. С каждым окном в системе Windows связан дескриптор окна – специальное значение типа HWND , которое уникально идентифицирует окно в системе. После создания окна приложение получает его дескриптор и может управлять окном, передавая дескриптор окна в соответствующие функции управления окнами. Каждое графическое приложение создаёт, по крайней мере, одно окно, называемое главным окном приложения. Данное окно обеспечивает основной интерфейс между пользователем и приложением. Для отображения или получения дополнительной информации, приложение может создавать и другие окна. Прежде чем создать окно, необходимо задать его свойства, т.е. задать набор атрибутов, которые система будет использовать для создания нового окна. Каждое окно – это экземпляр одного из зарегистрированных в системе классов окон. Классы окон, определённые в рамках текущего процесса, используются независимо от классов окон, определённых в других процессах. Для задания свойств окна используется структура WNDCLASSEX , содержащая ряд полей данных, в которых содержится соответствующая информация. После заполнения значений полей данных информация передаётся системе Windows в целях создания окна. Определение структуры WNDCLASSEX представлено ниже. typedef struct _WNDCLASSEX{ UINT cbSize; // размер этой структуры в байтах UINT style; // стили главного окна WNDPROC lpfnWndProc;// адрес оконной процедуры int cbClsExtra; // количество дополнительных байт, // занимаемых классом int cbWndExtra; // количество дополнительных байт, // занимаемых окном HINSTANCE hInstance;// дескриптор экземпляра // приложения HICON hIcon; // дескриптор большой иконки окна HCURSOR hCursor; // дескриптор курсора окна HBRUSH hbrBackground; // дескриптор кисти, // используемой для заливки фона LPCTSTR lpszMenuName; // имя для меню LPCTSTR lpszClassName; // имя класса окна HICON hIconSm; // дескриптор маленькой иконки окна } WNDCLASSEX; Смысл полей структуры WNDCLASSEX следующий: • Стили класса окна – набор флагов, определяющих различные аспекты поведения и внешнего вида окна. Стили класса окна можно произвольным образом комбинировать при помощи побитовой операции «или». • Оконная процедура – это функция, определяемая приложением, которая служит для обработки сообщений, посылаемых окну. Все окна, создаваемые на основе некоторого класса окна, имеют общую оконную процедуру. • Дескриптор экземпляра приложения используется для разделения классов окон, создаваемых различными модулями в рамках одного процесса. При запуске графического приложения им передаётся дескриптор экземпляра приложения. • Дескрипторы иконок задают внешний вид большой и маленькой иконок, отображаемых в панели задач, а также в заголовке окна. • Дескриптор кисти определяет способ заливки клиентской области окна. • Имя меню – имя ресурса меню, используемого окнами данного класса. • Имя класса окна – имя, под которым будет зарегистрирован данный класс окна. При создании нового окна приложение указывает имя класса окна, а также дескриптор экземпляра приложения, в котором данный класс был объявлен. Прежде чем задать свойства окна сначала необходимо создать объект типа WNDCLASSEX : WNDCLASSEX wc; После создание объекта этой структуры следует заполнить поля подходящими значениями. Для создания обычного окна заполнение может выглядеть следующим образом: wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW | CS_VREDRAW ; wc.lpfnWndProc = WinProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "WinClass"; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); Первым полем структуры WNDCLASSEX является cbSize . Эта переменная хранит размер объекта. При передаче объекта по указателю этим значением можно воспользоваться, чтобы определить точный объём памяти, занимаемый объектом. По большей части указание размера является мерой предосторожности, но это поле всегда следует заполнять. Следующее поле – style . Оно определяет поведение окна. Поле заполнено комбинированием констант CS_HREDRAW и CS_VREDRAW посредством оператора «или». Некоторые из допустимых значений приведены в табл. 1. Таблица 1. Стили поведения окна Значение Действие CS_HREDRAW Обновляет изображение всего окна, если перемещение или подстройка размера изменяет ширину окна CS_VREDRAW Обновляет изображение всего окна, если перемещение или подстройка размера изменяет высоту окна CS_OWNDC Упрощает рисование в окне CS_DBLCLKS Посылает сообщение о двойном щелчке, произошедшем в области окна CS_NOCLOSE Отключает команду Close (Закрыть) системного меню окна Следующее поле определяет функцию обработки событий, получаемых от системы Windows wc.lpfnWndProc = WinProc; В этом объявлении функция названа WinProc , хотя она может иметь любое имя. Установка этого значения говорит Windows, какую из функций вызывать, когда для окна имеются входные данные. Следующее поле, hInstance , является дескриптором экземпляра приложения. Windows предоставляет значение этого параметра в качестве аргумента hInst , полученным функцией WinMain : wc.hInstance = hInst; Вызов функции Windows LoadIcon позволяет инициализировать следующее поле – hIcon . Можно использовать произвольную пиктограмму, в примере заполнения структуры WNDCLASSEX была использована системная пиктограмма (то есть поставляемая в составе системы Windows). В табл. 2 перечислены некоторые из доступных системных пиктограмм. Таблица 2. Системные пиктограммы Значение Действие IDI_APPLICATION Стандартная пиктограмма приложения IDI_ASTERISK Пиктограмма звёздочки IDI_EXCLAMATION Восклицательный знак IDI_HAND Пиктограмма с ладонью IDI_QUESTION Вопросительный знак IDI_WINLOGO Логотип системы Windows Поле hCursor инициализируется практически таким же образом, при помощи функции LoadCursor hCursor указывает, как выглядит указатель мыши, когда находится в области окна. Некоторые из системных курсоров перечислены в табл. 3. Таблица 3. Системные курсоры Значение Действие IDC_ARRON Стандартный указатель IDC_APPSTARTING Стандартный указатель и маленькие песочные часы IDC_CROSS Перекрестие IDC_IBEAM Текстовый курсор IDC_NO Перечёркнутый круг IDC_SIZEALL Четырёхлепестковая стрелка IDC_SIZENESW Двулепестковая стрелка, указывающая на северо-восток и юго-запад IDC_SIZENWSE Двулепестковая стрелка, указывающая на северо-запад и юго-восток IDC_SIZENS Двулепестковая стрелка, указывающая на север и юг IDC_SIZEWE Двулепестковая стрелка, указывающая на запад и восток IDC_UPARROW Стрелка вверх IDC_WAIT Песочные часы Следующее поле, hbrBackground , определяет вид фона окна. Способ закрашивания фона определяется при помощи кистей. Кисть (brush) в системе Windows – это способ хранения информации о том, как следует заполнять область цветом. Некоторые из стандартных кистей перечислены в табл. 4. Таблица 4. Системные кисти Значение Действие BLACK_BRUSH Сплошной чёрный WHITE_BRUSH Сплошной белый GRAY_BRUSH Сплошной серый LTGRAY_BRUSH Сплошной светло-серый DKGRAY_BRUSH Сплошной тёмно-серый NULL_BRUSH Пустая кисть Для того, организовать в окне меню, следует использовать поле lpszMenuName и определить состав меню, в противном случае следует установить значение NULL Следующее поле даёт имя классу, который служит для создания окна. Каждое окно является объектом. В процессе заполнения структуры WNDCLASSEX будет создан новый класс. Затем на основе этого класса создаётся окно. Классу можно дать любое удобное имя, поскольку в действительности это имя особого значения не имеет. Последнее поле хранит уменьшенную версию пиктограммы. Именно эта версия отображается в заголовке окна и на панели задач. Значение этому полю присваивается так же, как полю hIcon : wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); После заполнения полей структуры WNDCLASSEX , приложение должно вызвать системную функцию RegisterClassEx , передав ей адрес данной структуры. Функция возвращает логическое значение, отражающий результат работы ( true – функция завершилась успешно, false – в противном случае). Ниже представлен вариант регистрации класса окна. if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Cannot register class", "ERROR",MB_OK); return 0; } После успешной регистрации окна необходимо создать его экземпляр посредством вызова функции CreateWindowEx , которая имеет следующее объявление: HWND CreateWindowEx ( DWORD dwExStyle, // дополнительные стили LPCTSTR lpClassName, // имя класса LPCTSTR lpWindowName, // имя окна DWORD dwStyle, //стиль int x, // расстояние до окна от левой стороны экрана int у, // расстояние до окна от верхней стороны экрана int nWidth, // ширина окна int nHeight, // высота окна HWND hWndParent, // дескриптор родительского окна HMENU hMenu, // дескриптор меню НINSTANCE hInst, // дескриптор экземпляра приложения LPVOID lpParam // параметры создания окна ); Эта функция возвращает значение либо NULL , если создание окна прошло неудачно, либо дескриптор созданного окна в противном случае. Чтобы работать с окном впоследствии, для хранения дескриптора необходимо создать переменную HWND hWnd; Первый параметр функции, dwExStyle , хранит все дополнительные режимы для окна. Если дополнительные режимы не требуются, следует использовать значение NULL Второй параметр – имя класса, используемого для создания окна. В нашем случае – "WinClass" Третий параметр – текстовый заголовок окна. Четвертый параметр, dwStyle , определяет вид и поведение окна. Стили окна можно произвольным образом комбинировать при помощи побитовой операции «или». Некоторые из значений перечислены в табл. 5. Таблица 4. Стили окон Значение Действие WS_POPUP Всплывающее окно WS_OVERLAPED Перекрываемое окно с заголовком и границами WS_OVERLAPEDWINDOW Перекрываемое окно со стилями WS_DVERLAPPED , WS_CAPTION , WS_SYSMENU , WS_THICKFRAME , WS_MINIMIZEBOX и WS_MAXIHIZEBOX WS_VISIBLE Изначально видимое окно WS_SYSMENU Системное меню доступно в заголовке окна (по щелчку на маленькой пиктограмме). Должен использоваться стиль WS_CAPTION WS_BORDER Окно с тонкими границами WS_CAPTION Окно с заголовком (стиль WS_BORDER включается автоматически) WS_MINIMISE Окно изначально свёрнуто WS_MAXIMIZE Окно изначально имеет максимальный размер Параметры x и y определяют расстояние от левого верхнего угла экрана до левого верхнего угла окна. Чтобы оставить эти параметры на усмотрение Windows, можно воспользоваться значением CW_USEDEFAULT вместо конкретного числа. Параметры nWidth и nHeight определяют ширину и высоту окна. Можно воспользоваться константой CW_USEDEFAULT , чтобы система задала их самостоятельно. Параметр hWndParent определяет дескриптор родительского окна, если таковое существует. Значение NULL делает родительским окном рабочий стол Windows. Параметр hMenu определяет дескриптор связанного с окном меню. При передаче NULL в качестве данного параметра, создаваемое окно не будет иметь меню. Параметр hInst указывает на дескриптор экземпляра приложения, который передаётся в WinMain Параметр lpParam содержит дополнительные параметры, например, данные связанные с окном. Данный параметр используется также при создании окон в приложениях с многодокументным интерфейсом. По умолчанию этот параметр выставляется в NULL Окончательный вызов функции CreateWindowEx может выглядеть следующим образом: hWnd = CreateWindowEx ( NULL, //дополнительные стили "WinClass", //имя класса "Простое окно", //заголовок окна WS_OVERLAPPEDWINDOW | WS_VISIBLE, //стили CW_USEDEFAULT, CW_USEDEFAULT, //начальное положение CW_USEDEFAULT, CW_USEDEFAULT, //начальный размер NULL, //родительским окном является рабочий стол NULL, //меню отсутствует hInst, //дескриптор экземпляра приложения NULL); //дополнительные параметры При успешном создании окна функция возвращает дескриптор созданного окна, который приложение может использовать для управления окном. В примере вызова функции CreateWindowEx был использован стиль WS_VISIBLE , который делает окно изначально видимым. В отсутствие этого стиля чтобы отобразить окно необходимо вызвать функцию ShowWindow Функция ShowWindow имеет два параметра: дескриптор окна и аргумент nCmdShow , полученный функцией WinMain . Вот так можно самостоятельно отобразить окно: ShowWindow(hWnd, nCmdShow); И в заключение следует вызвать функцию UpdateWindow , которая сразу же обновляет окно на экране: UpdateWindow(hWnd); Эта функция посылает событие WM_PAINT , которое сообщает, что клиентская область окна или её часть нуждается в перерисовке. После создания окна необходимо приступить к обработке поступающих событий. Для этого используется функция, указанная в поле lpfnWndProc структуры WNDCLASSEX . В рассмотренном выше примере заполнения структуры WNDCLASSEX эта функция названа WinProc Для получения событий, которые подлежат обработке, предназначена функция GetMessage . Эта функция помещается в условие цикла, и работа цикла зависит от значений, которая она возвращает. Любое ненулевое значение, возвращаемое функцией GetMessage , означает, что очередь событий не пуста. Объявление функции GetMessage следующее: BOOL GetMessage (LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax); Функция заполняет структуру lpMsg информацией о полученном сообщении. Оставшиеся три параметра можно игнорировать. Они задействованы только в очень сложных программах. В качестве первого аргумента следует передать ссылку на структуру MSG : typedef struct tagMSG { HWND hwnd; // окно, в котором создано сообщение UINT message; // идентификатор сообщения WPARAM wParam; // дополнительная информация LPARAM lParam; // дополнительная информация DWORD time; // время создания сообщения POINT pt; // координаты указателя мыши } MSG; До передачи функции GetMessage объект необходимо создать, после чего реализовать цикл, в котором происходит получение событий, поступаемых от системы Windows. Это может выглядеть следующим образом: MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { } После получения сообщений необходимо выполнить их обработку, которая может быть реализована при помощи функций TranslateMessage и DispatchMessage . Аргументом каждой из них является ссылка на объект MSG Функция TranslateMessage производит предварительную обработку полученной информации, а функция DispatchMessage посылает сообщение, подлежащее обработке, функции WinProc . Таким образом, код обработки сообщений выглядит следующим образом: MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } Окончательный вариант функции WinMain будет следующим int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) { HWND hWnd; MSG msg; WNDCLASSEX wc; wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW | CS_VREDRAW ; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpfnWndProc = WinProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszClassName = "WinClass"; wc.lpszMenuName = NULL; wc.hIconSm = LoadIcon(NULL, IDI_WINLOGO); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Cannot register class", "ERROR",MB_OK); return 0; } hWnd = CreateWindowEx (NULL, "WinClass", "Простое окно", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL); if(!hWnd){ MessageBox(NULL, "Cannot create window", "ERROR",MB_OK); return 0; } ShowWindow(hWnd,nCmdShow); UpdateWindow(hWnd); while(GetMessage(&msg,NULL,0,0)){ TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } При необходимости передать приложению некоторую информацию, операционная система уведомляет приложение, посылая необходимое сообщение в соответствующее окно приложения. Каждое окно имеет особую функцию, называемую оконной процедурой, которую система вызывает всякий раз, когда для окна имеются входные данные. Оконная процедура объявляется следующим образом: LRESULT CALLBACK WinProc( HWND hWnd, // дескриптор окна UINT uMsg, // идентификатор сообщения WPARAM wParam, // дополнительный параметр 1 LPARAM lParam); // дополнительный параметр 2 Квалификатор |