Win32 api программирование
Скачать 0.78 Mb.
|
1.3. Создание и показ окна Для создания любых окон, в том числе и окон элементов управле- ния, используется функция Windows CreateWindowEx(), прототип ко- торой приведен ниже: HWND CreateWindowEx( DWORD dwExStyle, //расширенный стиль окна, //применяется совместно //со стилем dwStyle LPCTSTR lpClassName, //адрес строки с именем //зарегистрированного класса, // либо имя одного из //предопределенных классов LPCTSTR lpWindowName //адрес строки с //заголовком главного окна DWORD dwStyle, //стиль окна int x //горизонтальная позиция верхнего //левого угла окна int y, //вертикальная позиция верхнего //левого угла окна int nWidth, //ширина окна в пикселях 14 int nHeight, //высота окна в пикселях HWND hWndParent,//дескриптор родительского окна HMENU hMenu, //дескриптор меню окна или //идентификатор элемента управления HINSTANCE hInstance, //дескриптор //экземпляра приложения LPVOID lpParam //указатель на //дополнительные данные ); Первый параметр − dwExStyle − задает расширенный стиль ок- на, который можно задать одним или несколькими флагами, используя побитовую операцию ИЛИ. Флаги расширенных стилей: • WS_EX_MDICHILD – создать дочернее окно многодокументного интерфейса; • WS_EX_TOOLWINDOW – создать окно с инструментами, предназна- ченное для реализации плавающих панелей инструментов; • WS_EX_ACCEPTFILES – создать окно, которое принимает пере- таскиваемые файлы. Расширенный стиль dwExStyle применяется совместно со стилем, который определяется четвертым параметром dwStyle. Полный список расширенных стилей см. в MSDN. Второй параметр − lpClassName – указатель на строку, содержа- щую имя зарегистрированного функцией RegisterClassEx() класса, либо имя одного из предопределенных классов. Вызывая функцию CreateWindowEx() многократно, можно соз- дать много окон данного класса, различающихся, например, размерами и местоположением на экране. Окна предопределенных классов необходи- мо создавать как дочерние. Предопределенные классы окон, реализую- щие различные элементы управления: • BUTTON – кнопки, группы, флажки, переключатели или пикто- граммы (префикс в обозначении стиля – BS_); • COMBOBOX – комбинированный список с полем редактирования в верхней части или выпадающий список выбора (элементы LISTBOX и EDIT) (префикс в обозначении стиля – CBS_); • EDIT– поле редактирования , предназначенное для ввода текста с клавиатуры (префикс в обозначении стиля –ES_); • LISTBOX – элемент управления списком строк, из которого можно выбрать любую строку или несколько строк (стили LBS_OWNERDRAWFIXED и LBS_OWNERDRAW позволяют управ- лять видом строки) (префикс в обозначении стиля –LBS_); • MDICLIENT – клиентское окно многодокументного интерфейса; • RICHEDIT – элемент управления в дополнение к EDIT − позво- ляет редактировать текст с разными шрифтами и стилями (пре- фикс в обозначении стиля – ES_); • RICHEDIT_CLASS – усовершенствованная версия RICHEDIT (префикс в обозначении стиля – ES_); 15 • SCROLBAR – элемент управления полосой прокрутки (слайдер) (префикс в обозначении стиля – SBS_); • STATIC – элемент управления статическим текстом − использу- ется для размещения в окне текста, рамок или как контейнер для других элементов управления (префикс в обозначении стиля – SS_). Третий параметр − lpWindowName функции CreateWindowEx() − определяет адрес строки с именем окна. Место отображения имени зависит от вида окна, например: • главное окно приложения – имя выводится в верхнюю часть ок- на как заголовок окна; • дочернее окно класса BUTTON – имя размещается по центру кнопки. Четвертый параметр dwStyle определяет стиль окна. С помощью стиля задаются такие характеристики окна, как вид окружающей его рам- ки, наличие системного меню, присутствие линеек вертикальной и гори- зонтальной прокрутки и т.п. Побитовая операция ИЛИ (знак |) позволяет набрать требуемый комплект свойств. Обычно главное окно описывается константой WS_OVERLAPPEDWINDOW(0x00CF0000). Это перекры- вающееся окно с заголовком, системным меню, кнопками минимизации и максимизации, кнопкой закрытия окна и «толстой» рамкой, позволяющей изменять размеры окна. Пятый параметр x и шестой параметр y – экранные координаты верхнего левого угла главного окна, т.е. координаты относительно начала экрана в пикселях. Для дочерних окон и элементов управления эти коор- динаты отсчитываются относительно левого верхнего угла родительского окна и измеряются в пикселях. Если позиция x не важна, то можно уста- новить значение x равным CW_USEDEFAULT – значение по умолчанию. В этом случае параметр y игнорируется. Седьмой и восьмой параметры nWidth и nHeight – ширина и высота окна в пикселях. Если параметрам nWidth и nHeight присвоено значение CW_USEDEFAULT, то для них будут использоваться значения по умолчанию. Девятый параметр hWndParent – это дескриптор родительского окна; для главного окна, у которого нет родителя, используется константа HWND_DESKTOP или NULL. Десятый параметр hMenu функции CreateWindowEx() содержит дескриптор меню окна или идентификатор элемента управления Интерпретация значения параметра hMenu зависит от вида окна: • приложение использует меню, определенное полем lpszMenu структурной переменной типа WNDCLASSEX (класс окна). В этом случае параметру hMenu необходимо присвоить значение NULL; 16 • приложение создает элемент управления как дочернее окно. В этом случае параметру hMenu присваивается целочисленное значение, используемое далее как идентификатор созданного элемента (этот идентификатор будет содержаться в сообщении WM_COMMAND, поступающего от созданного элемента управле- ния). Одиннадцатому параметру hInstance должно быть присвоено значение дескриптора экземпляра приложения (значение аргумента hInstance главной функции WinMain). Последний параметр lpParam функции CreateWindowEx() – указатель на дополнительные данные, передаваемые окну в момент его создания при обработке сообщения WM_CREATE, или значение NULL. В сообщениях WM_CREATE и WM_NCCREATE параметр lрParam содержит указатель на структуру CREATESTRUCT, в которую будут зане- сены параметры функции CreateWindowEx(). Символическое обозначение NULL ((void*)0) используется в тех случаях, когда для некоторой функции надо указать нулевое значение параметра, являющегося указателем. Функция CreateWindowEx() при успешном завершении возвра- щает дескриптор созданного окна, т.е. локальную переменную hWnd. Де- скриптор окна hWnd передается как параметр в функцию ShowWindow(), которая организует вывод созданного окна на экран. Функция ShowWindow() имеет следующий прототип: BOOL ShowWindow( HWND hWnd, // дескриптор окна int nCmdShow // вид показанного окна ); Параметр nCmdShow определяет, в каком виде будет показано ок- но. При начальном отображении главного окна рекомендуется присваи- вать второму параметру значение, которое было получено через параметр nCmdShow главной функции WinMain. Вызов ShowWindow() влечет за собой генерацию сообщений WM_SIZE и WM_MOVE. При обработке сообщения WM_SIZE сис- тема всегда генерирует сообщение WM_PAINT. 1.4. Обработка сообщений В ООП управляющие данные принято называть сообщениями. Эта терминология используется и в Windows. Сообщения являются реакцией системы на происходящие в ней события и единственным средством свя- зи окна (и всего приложения) с операционной системой. Коды сообщений Windows имеют единый формат. Это 32-битные целые без знака (для системных сообщений они принимают значения от 1 до 0x3FF), которым для лучшей читаемос- ти присвоены параметрические имена, т.е. каждому коду соответствует символическая константа. Например, аппаратные сообщения: 17 • WM_MOUSMOUVE – 200h (реакция на перемещение мыши); • WM_LBUTTONDOWN – 201h (реакция на нажатие левой клавиши мыши); • WM_TIMER – 113h (реакция на срабатывания таймера); • WM_MOVSEACTIVATE–0021h (активизировать мышь). Сообщения могут возникать и в результате программных действий системы. Например, при создании и выводе главного окна система посы- лает в приложение следующие сообщения: • WM_GETMINMAXINFO (для уточнения размеров окна); • WM_ERASEBKGND (при заполнении окна цветом фона); • WM_SIZE (оценка размера рабочей области); • WM_PAINT (перерисовка окна). Сообщения могут создаваться в прикладной программе и посы- латься в Windows для того, чтобы система выполнила некоторые дейст- вия, например, заполнила информацией окно со списком или сообщила о состоянии элемента управления. Номера таких сообщений превышают значение 0x3FF. Сообщения могут создаваться и непосредственно программистом. Для каждого потока в Win32 создается своя очередь сообщений, которая не имеет фиксированной длины. Сообщения из системной очере- ди не передаются в приложение в целом, а распределяются по его пото- кам. Главный цикл обработки сообщений в простейшем виде состоит из следующих предложений языка: 2while(GetMessage(&Msg, NULL, 0, 0)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } Назначение цикла обработки сообщений – получить сообщения, поступающие в приложение, и вызвать в ответ на каждое сообщение оконную функцию. Задача оконной функции – выполнить требуемую об- работку поступившего сообщения. В цикле вызывается функция Windows GetMessage(), которая анализирует очередь сообщений своего потока и, если в очереди обнару- живается сообщение, изымает его и переносит в структурную перемен- ную типа MSG, предназначенную для приема сообщений. Структура типа MSG описана в файле winuser.h следующим обра- зом: typedef struct tagMSG{ HWND hWnd; //дескриптор (хэндл) окна, //которому передано сообщение UINT message; //код данного сообщения //(идентификатор) WPARAM wParam; //дополнительная информация LPARAM lParam; //дополнительная информация DWORD time; //время отправления сообщения POINT pt; //позиция курсора мыши на момент 18 //отправления сообщения }Msg; //новое имя для типа tagMSG. Интерпретация параметров wParam и lParam зависит от кода со- общения (message). Тип данных POINT используется для представления точки парой ее координат и описан следующим образом: typedef struct tagPOINT{ LONG x; LONG y; } POINT; Из структуры MSG следует, что содержимое сообщения представля- ет собой пакет из шести данных. Прототип функции GetMessage() имеет следующий вид: BOOL GetMessage( LPMSG lpMsg, //указатель на структуру переменную типа MSG HWND hWnd, //дескриптор окна, принимающего cообщение UINT uMsgFilterMin, //максимальный номер сообщения INT uMsgFilterMax //минимальный номер сообщения ); Параметр lpMsg задает адрес структурной переменной типа MSG, в которую помещается выбранное из очереди сообщение. Параметр hWnd содержит дескриптор окна, принимающего сообще- ние. Если этот параметр равен NULL, функция GetMessage() работает со всеми сообщениями данного приложения. Параметры uMsgFilterMin и uMsgFilterMax указывают соот- ветственно минимальный и максимальный номера принимаемого сооб- щения. Если в качестве этих параметров указать константы WM_KEYFIRST и WM_KEYLAST, функция будет забирать из очереди только сообщения, генерируемые клавиатурой. Константы WM_MOUSFIRST и WM_MOUSLAST позволяют работать только с сообще- ниями от мыши. Чтобы исключить фильтрацию сообщений, необходимо, чтобы оба параметра были равны нулю. Функция GetMessage() завершится с возвратом значения TRUE лишь после того, как очередное сообщение попадет в структурную пере- менную Msg. Далее вызываются функции Windows TranslateMessage() и DispatchMessage(), которые имеют следующие прототипы: BOOL TranslateMessage(CONST MSG* lpMsg); LRESULT DispatchMessage(CONST MSG* lpMsg); Функция TranslateMessage() преобразует аппаратные сооб- щения от клавиатуры WM_KEYDOWN (клавиша нажата) и WM_KEYUP (кла- виша отпущена) в символьное сообщение WM_CHAR. Параметр wParam этого сообщения содержит код символа. Сообщение WM_CHAR помещает- ся в очередь, и на следующей итерации цикла функция GetMessage() извлекает его для последующей обработки. Вызов функции Translate- Message() необходим только в тех приложениях, которые обрабаты- вают ввод данных с клавиатуры. 19 Далее функция DispatchMessage() вызывает оконную функ- цию того окна, которому предназначено данное сообщение, и передает ей содержимое сообщения из структурной переменной типа Msg (первые че- тыре поля). Если программе необходимы элементы time и pt, то их можно извлечь непосредственно из структурной переменной. После того как оконная функция обработает сообщение, возврат из нее приводит к возврату из функции DispatchMessage() на продолжение цикла while Если функция GetMessage() обнаруживает в очереди сообщение WM_QUIT (код 0x12), то она завершается с возвратом значения FALSE, что приводит к завершению цикла и переходу на предложение re- turn Msg.wParam; т.е. к завершению главной функции и всего при- ложения. Если функция GetMessage() не обнаруживает сообщений в оче- реди потока, система останавливает выполнение данного потока и пере- водит его в «спящее» состояние. Такое состояние потока не потребляет процессорного времени и не тормозит работу системы. Поток возобновит свою работу, как только в очереди появится сообщение. Вместо функции GetMessage() часто используют функцию PeekMessage(), которая имеет следующий прототип: BOOL PeekMessage( LPMSG lpMsg , //адрес структурной переменной //с сообщением HWND hWnd , //дескриптор окна UINT wMsgFilterMin , //Min номер выбираемого //сообщения UINT wMsgFilterMax , //Max номер выбираемого //сообщения UINT wRemoveMsg //флаг удаления сообщения ); Первые четыре параметра функции PeekMessage() совпадают с параметрами функции GetMessage(). Пятый параметр wRemoveMsg определяет, как должно быть вы- брано сообщение из очереди, а именно: • PM_NOREMOV – сообщение выбирается и не удаляется из очереди; • PM_REMOV – сообщение выбирается и удаляется из очереди. Функция PeekMessage() не ждет, когда сообщение поступит в очередь сообщений, а сразу возвращает управление. Если сообщения в очереди нет, то функция возвращает нуль, а если сообщение находится в очереди, оно помещается в структурную переменную типа MSG и удаля- ется из очереди сообщений (флаг PM_REMOV) или не удаляется (флаг PM_NOREMOV). Функция PeekMessage() часто используется для оптимизации работы программы. Если сообщение не находится в очереди сообщений, то в свободное время можно выполнять какую-либо другую работу. Этот прием часто встречается в программах, выполняющих графическую ани- мацию, и более эффективен, чем использование сообщений от таймера. 20 Главный цикл обработки сообщений с применение функции Peek- Message() может выглядеть следующим образом: while(1) { if(PeekMessage(&Msg,NULL,0,0, PM_REMOV)) { if(Msg.message==WM_QUIT) break; TranslateMessage(&Msg); DispatchMessage(&Msg); } } 1.5. Оконная функция Оконная функция – это функция обратного вызова, предназначен- ная для обработки сообщений, адресованных окну того оконного класса, в котором содержится ссылка на данную процедуру. Функции обратного вызова – это функции, которые вызывает сама операционная система. Компилятор определяет их по спецификатору CALLBACK. Оконная функция получает четыре параметра, а ее заголовок имеет стандартный синтаксис: LRESULT CALLBACK Имя_функции( HWND hWnd, //дескриптор (хэндл) окна, которому //предназначено данное сообщение UINT uMsg //код пришедшего сообщения WPARAM wParam //дополнительная информация //о сообщении LPARAM lParam //дополнительная информация //о сообщении ); Имя функции может быть произвольным, но для главного окна приложения обычно используется имя WndProc. В теле оконной функ- ции после объявления необходимых локальных переменных используется оператор switch…case. Например: LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(Msg) { case WM_CREATE: //… return TRUE; case WM_KEYDOWN: /* Обрабатываем сообщение WM_KEYDOWN (нажатие клавиши) */ switch(wParam) { /* Клавиша Esc */ case VK_ESCAPE: 21 SendMessage(hWnd,WM_CLOSE,0,0); break; } break; case WM_DESTROY: /* Функция PostQuitMessage выполняет только одно действие, ставит в очередь сообщение WM_QUIT. Параметр у этой функции - код возврата, кото- рый помещается в Msg.wParam и возвращается главной функцией */ PostQuitMessage(0); break; default: /*Обработка прочих сообщений по умолчанию*/ return DefWindowProc(hWnd,msg,wParam,lParam); } return 0L; } Реально в программе требуется обрабатывать конкретные сообще- ния, а для обработки прочих сообщений предназначена функция Def- WindowProc() (Default Windows Procedure). Единственное сообщение, не входящее в «юрисдикцию» DefWin- dowProc, –сообщение об уничтожении окна WM_DESTROY, поэтому его обработка должна всегда присутствовать в оконной процедуре. Обычно приложения завершают свою работу по команде пользова- теля, например ALT+F4. В этом случае Windows убирает с экрана окно приложения и посылает сообщение WM_DESTROY не в очередь приложе- ния, а воконную функцию с непосредственным ее вызовом. Обработка этого сообщения должна состоять в освобождении ресурсов Windows. Например, при обработке сообщения WM_CREATE приложение могло создать и использовать в программе кисти, перья, шрифты, устано- вить таймеры, динамически выделить память т.п. При завершении при- ложения эти ресурсы необходимо освободить. Далее необходимо вызвать функцию PostQuitMessage(0); Все сообщения, обработанные в оконной процедуре, должны возвращать стандартное значение – нуль по вы- ходу из процедуры. Однако бывают случаи, когда тре- буется возвратить единицу или -1. Например, после обработки сообщения WM_NCCREATE, которое приходит перед сообщением WM_CREANT, следует вернуть единицу. Оконная функция может вызываться двумя способами: функцией DispatchMessage() и непосредственно программами Windows. |