|
|
Основы создания графических приложений в системе Windows
Графический интерфейс пользователя Разновидность пользовательского интерфейса, в котором элементы интерфейса представленные пользователю на дисплее, исполнены в виде графических изображений
Функция WinMain() Подобно тому как функция main() является точкой входа консольного приложения, функция WinMain является точкой входа в GUI-приложение системы Windows Задачи функции WinMain: Инициализация приложения Отображение главного окна приложения Цикл выборки и обработки сообщений Возврат целочисленного значения в операционную систему
Простейшее приложение Windows int APIENTRY WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/) { // возвращаемся в операционную систему return 0; }
Windows и Окна В GUI приложении Windows окно – это прямоугольная область на экране, служащая для отображения выводимой информации и получения пользовательского ввода Windows – многозадачная ОС Несколько одновременно запущенных приложений Область экрана – общая для всех окон в системе Только одно окно может в заданный момент времени получать вводимую информацию от пользователя
Главное окно приложения Служит для обработки сообщений и получения данных, введенных пользователем Является родительским для окон, создаваемых в приложении Возможно существование нескольких главных окон в рамках одного приложения Приложение Microsoft Word Интернет –браузер Такие приложению завершают работу после закрытия всех своих окон
Элементы окна
Области окна Клиентская область Часть окна, служащая для вывода текста и графики, а также для получения пользовательского ввода Управляется приложением Неклиентская область область заголовка, меню, рамку, области прокрутки, кнопки минимизации/максимизации и закрытия окна Как правило, управляется операционной системой
Элементы управления (controls) Вспомогательные окна, служащие для ввода и вывода определенной информации Поля редактирования (Edit box) Статический текст (Static) Кнопки (Button, Radio button, Check Box) Списки (List box, Combo box, List) Деревья (Tree control) Создаваемые пользователем компоненты
Диалоговые окна Диалоговое окно – это окно, содержащее один или более элементов управления Обычно не содержат меню или полос прокрутки, кнопок минимизации/максимизации Используются для ввода пользователем различных данных Типы диалоговых окон Модальные Немодальные
Диалоговые окна Модальное окно Немодальное окно
Стандартные диалоговые окна Окно выбора файла Окно выбора шрифта Окно выбора цвета Окно выбора принтера Окно выбора папки Окно настройки свойств страницы
Пример диалогового окна
Окна сообщений (Message boxes) Специальные диалоговые окна, служащие для отображения коротких сообщений пользователю: Предупреждение об ошибке Уведомление о завершении результатах операции
Пример окна сообщений
Приложение HelloWorld int APIENTRY WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/) { MessageBox( NULL, "Hello World", "Hi", MB_OK | MB_ICONINFORMATION ); return 0; }
Окно рабочего стола (Desktop Window) Данное окно автоматически создается при загрузке ОС Окно рабочего стола служит для отображения заднего фона окна и служит основой для размещения других окон
Создание окна При создании окна приложение должно указать следующие атрибуты окна: Имя класса окна Имя окна Стиль окна и дополнительный стиль окна Положение и размер окна Дескриптор родительского окна или окна-владельца Дескриптор меню или дочернего окна Дескриптор экземпляра приложения Данные, характерные для приложения
Имя класса окна (Window Class Name) Класс окна – это определенный набор атрибутов, используемый в качестве шаблона при создании окон Каждое окно относится к определенному классу На основе класса окна приложение может создать произвольное количество окон Окна, принадлежащие к одному классу ведут себя сходным образом Кнопки нажимаются Выпадающие списки выпадают Поля редактирования текста позволяют редактировать текст
Предопределенные классы окон В системе зарегистрированы предопределенные классы окон BUTTON LISTBOX COMBOBOX STATIC EDIT MDICLIENT RICHEDIT_CLASS SCROLLBAR И др.
Регистрация класса окна Главное окно приложения не имеет предопределенного класса, поэтому приложению необходимо зарегистрировать класс своего главного окна самостоятельно Регистрация класса окна осуществляется при помощи функции RegisterClassEx()
Имя окна Строка, идентифицирующая данное окно для пользователя Главное окно приложения и диалоговые окна отображают имя окна в строке заголовка Некоторые элементы управления – внутри клиентской области Edit box, Static text, Button Некоторые элементы управления – не отображают вообще List box, Combo box
Стили окна Стиль окна – именованная целочисленная константа, определяющая определенные аспекты поведения и внешнего вида окна Тип рамки Наличие и вид заголовка Наличие кнопок максимизации/минимизации И т.п. Окно может иметь несколько стилей окна Объединяются при помощи операции | Некоторые стили могут быть применены ко всем окнам, в то время как другие – к окнам определенного класса Стиль ES_PASSWORD применим только к полям редактирования текста Стиль WS_VISIBLE – к любым окнам
Положение и размеры окна Положение и размеры окна задаются в пикселях Положение окна – координаты верхнего левого угла окна относительно верхнего левого угла экрана, либо относительно родительского окна (для дочерних окон)
Дескриптор родительского окна Некоторые окна могут иметь родителей такие окна называются дочерними Родительские окна определяют систему координат своих дочерних окон Окна без родителей – окна верхнего уровня (Top Level Window)
Идентификатор меню или идентификатор дочернего окна Дочерние окна могут иметь идентификатор дочернего окна – уникальное значение, ассоциированное с данным дочерним окном Система позволяет получить дескриптор дочернего окна по его идентификатору при помощи функции GetDlgItem Окна, не являющиеся дочерними, могут иметь меню
Окно с меню
Дескриптор экземпляра приложения (HINSTANCE) Является идентификатором экземпляра запущенного приложения, либо загруженного DLL-модуля Передается в качестве параметра функции WinMain Для DLL-модулей – в DLL Main Используется при создании окон, работы с ресурсами, потоками выполнения и т.п. Разные модули внутри одного процесса могут регистрировать свои собственные классы окон, даже совпадающие по имени
Дескриптор Окна (Window Handle) Каждое окно в системе после своего создания получает дескриптор – уникальный идентификатор, однозначно определяющий данное окно в системе Данный идентификатор имеет тип HWND Используется для управления созданным окном
Создание окна на основе зарегистрированного класса Создание окна осуществляется при помощи функции CreateWindowEx() После своего создания окно является невидимым Чтобы показать его, необходимо вызвать функцию ShowWindow() Можно создать окно видимым изначально, задав ему стиль WS_VISIBLE при его создании
Сообщения Обработка сообщений лежит в основе работы приложений Windows Сообщения создаются системой и приложением в ответ на каждое событие, происходящее в Windows: Движения мыши, нажатие клавиш, события таймера и т.п. Многие GUI-приложения проводят большую часть времени в ожидании сообщений Это позволяет оптимально использовать ресурсы процессора в условиях параллельной работы нескольких приложений
Что такое сообщение? Сигнал, посылаемый приложению системой или другими приложениями при наступлении определенного события В Windows SDK структура MSG определена следующим образом: typedef struct tagMSG { HWND hwnd; // дескриптор окна UINT message; // идентификатор сообщения WPARAM wParam; // параметр wParam LPARAM lParam; // параметр lParam DWORD time;// время отправки сообщения POINT pt; // положение курсора мыши в момент создания сообщения } MSG;
Маршрутизация сообщений и очередь сообщений Очередь сообщений – объект для временного хранения сообщений Системная очередь сообщений Хранит сообщения от устройств ввода Очередь сообщений GUI-потока (thread) Получает сообщения из системной очереди сообщений, адресованные окнам, созданным в данном потоке
Обработка сообщений GUI-поток выбирает сообщения из своей очереди с использованием цикла выборки сообщений
Цикл выборки (обработки) сообщений Функция GetMessage() осуществляет выбор сообщения из очереди сообщений Функция TranslateMessage() осуществляет перевод нажатий виртуальных клавиш в символьные сообщения, которые будут считаны при следующем вызове GetMessage() или PeekMessage() Функция DispatchMessage() перенаправляет сообщение из цикла обрабоки в соответствующую оконную процедуру
Простейший цикл обработки сообщений MSG msg; BOOL res; while ((res = GetMessage(&msg, NULL, 0, 0)) != 0) { if (res == -1) { // произошла ошибка - нужно обработать ее и, вероятно, // завершить работу приложения } else { // Если это сообщение о нажатии виртуальной клавиши, // то добавляем в очередь сообщений сообщения, несущие информацию о // коде вводимого пользователем символа TranslateMessage(&msg); // передаем сообщение в соответствующую оконную процедуру DispatchMessage(&msg); } }
Оконная процедура Каждое окно имеет связанную с ним оконную процедуру Оконная процедура – функция внутри приложения, предназначенная для обработки сообщений данного класса окон Windows вызывает соотв. оконную процедуру при вызове DispatchMessage Все окна, относящиеся к данному классу используют одну и ту же оконную процедуру по умолчанию Поведение и внешний вид окна определяются реакцией оконной процедуры на получаемые сообщения
Регистрация оконной процедуры Регистрация оконной процедуры происходит одновременно с регистрацией класса окна Приложение может создать произвольное количество окон, относящихся к данному классу и использующих одну и ту же оконную процедуру Аккуратная работа с глобальными переменными Оконная процедура должна быть реентерабельной, т.е. должна позволять ее повторный вызов явным или неявным образом из самой себя. Минимум локальных переменных внутри оконной процедуры
Требования к оконной процедуре Одна оконная процедура может обрабатывать несколько окон одновременно Умеренное использование глобальных переменных Оконная процедура должна быть реентерабельной Возможен неявный рекурсивный вызов оконной процедуры Минимизировать количество локальных переменных внутри оконной процедуры Борьба со Stack Overflow
Структура оконной процедуры Оконная процедура имеет следующий прототип: LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Оконная процедура по умолчанию Для многих оконных сообщений в системе предусмотрено поведение по умолчанию Перемещение окон Минимизация/максимизация Реакция на движения мыши Все сообщения, не обрабатываемые явно в оконной процедуре приложения, должны направляться в оконную процедуру по умолчанию при помощи вызова функции DefWindowProc()
Пример простейшей оконной процедуры главного окна приложения LRESULT CALLBACK MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam); }
Перегрузка (Subclassing) оконной процедуры При создании окна система выделяет память для хранения информации об окне, включая адрес оконной процедуры При посылке сообщения окну система извлекает адрес оконной процедуры из информации, специфичной для окна с указанным дескриптором, и вызывает оконную процедуру Subclassing – технология, позволяющая перехватывать и обрабатывать в обход оригинальной оконной процедуры
Принцип SubClassing’а Приложение может заменить адрес оконной процедуры отдельно взятого окна или оконного класса адресом собственной оконной процедуры подкласса (subclass procedure) Subclassing возможет лишь в рамках одного процесса После этого новая оконная процедура сможет обрабатывать сообщения окна: Передача их в оригинальную оконную процедуру без изменения Модификация сообщения с последующей передачей его в оригинальную оконную процедуру Обработка сообщения
Виды Subclassing’а Instance subclassing У созданного окна заменяется адрес оконной процедуры Global Subclassing Подменяется адрес оконной процедуры целого класса окон
Superclassing Это технология, позволяющая создать новый класс окна с базовой функциональностью существующего класса + добавить собственную функциональность Часто применятся для расширения функционала существующих стандартных элементов управления
Часто используемые сообщения
Сообщение WM_CREATE Уведомление о том, что окно создается. Вызывается в ходе создания окна при помощи CreateWindowEx()
Сообщение WM_MOVE Посылается окну после его перемещения Сообщение WM_MOVING посылается окну во время его перемещения Приложение может изменить положение окна в обработчике данного сообщения
Сообщение WM_SIZE Посылается окну после изменения его размеров Сообщение WM_SIZING посылается во время изменения размеров окна Приложение может изменить размеры и положение окна в обработчике данного сообщения
Особенности графического вывода в многозадачной среде В многозадачных ОС одновременно могут работать несколько приложений В ОС Windows приложения могут создавать окна для визуального отображения информации и получения ввода пользователя Данные окна используют общую площадь экрана монитора, порой перекрывая друг друга
Эта ситуация динамически изменяется Подобно тому, как на обычном столе человек может перекладывать бумажные документы с места на место, пользователь графической ОС может переключаться между окнами, перемещать их по экрану При этом ранее закрытые области экрана и окон должны своевременно показывать пользователю ранее скрытую часть информации Такой подход позволяет обеспечить интуитивно понятное поведение графического интерфейса пользователя
Схема работы Каждое окно должно быть ответственным за корректное и своевременное отображение содержащейся в нем информации
Роль операционной системы Windows ОС Windows хранит информацию обо всех окнах в системе Пользовательские приложения не имеют прямого доступа к этой информации Все операции над окнами возможны только через функции ОС, принимающие дескриптор окна Windows отслеживает изменения во взаимном положении окон, определяет области требующие перерисовки и уведомляет приложения посредством отсылки сообщений
Недействительная область окна WM_ERASEBKGND WM_PAINT Приложение очищает задний фон окна Приложение производит рисование графического содержимого окна Область окна требующая отрисовки содержимого
Сообщение WM_ERASEBKGND Посылается окну в тот момент, когда его фон должен быть очищен Это подготовка недействительной области окна к отрисовке Приложение может использовать это сообщение для заполнения заднего фона окна каким-нибудь узором Оконная процедура по умолчанию просто заполняет задний фон кистью, указанной при регистрации класса окна
Сообщение WM_PAINT Посылается окну в том случае, когда какая-то часть его клиентской области требует перерисовки Приложение вызывало функцию RedrawWindow() или UpdateWindow() Область окна стала недействительной при сворачивании/перемещении окна на верхнем уровне
Обработка сообщения WM_PAINT LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_PAINT: { PAINTSTRUCT ps; HDC dc = BeginPaint(hWnd, &ps); // выполняем рисование // ... EndPaint(hWnd, &ps); } break; // обработка остальных сообщений } }
Сообщение WM_DESTROY Посылается окну после того как оно убрано с экрана перед его уничтожением Дочерние окна получают данное сообщение вслед за родительским При уничтожении главного окна приложения обычно происходит вызов функции PostQuitMessage()
Сообщение WM_QUIT Данное сообщение посылается потоку (а не окну) в качестве запроса на завершение его работы Функция GetMessage() возвращает значение 0 при извлечении сообщения WM_QUIT
Шаги для создания оконного приложения для ОС Windows Регистрация класса окна Создание главного окна приложения Выборка сообщений из цикла обработки сообщений Обработка сообщений в оконной процедуре окна
| URL: |
No comments posted yet
Comments