Программирование для IBM OS/2© Александр Фролов, Григорий ФроловТом 25, М.: Диалог-МИФИ, 1993, 286 стр. 4.4. Приложение TEXTOUTДля иллюстрации всего сказанного выше в этой главе мы приведем исходные тексты приложения TEXTOUT. В своем главном окне это приложение отображает строку Hello, PM!. Кроме того, если делать щелчки левой клавишей мыши в окне приложения, то в месте расположения курсора мыши будут отображаться его координаты (рис. 4.1).
Рис. 4.1. Главное окно приложения TEXTOUT Исходные тексты приложения представлены в листинге 4.1. Листинг 4.1. Файл textout\textout.c // ================================================= // Определения // ================================================= #define INCL_WIN #define INCL_GPI #define INCL_WINDIALOGS #include <os2.h> #include <stdio.h> #include <string.h> #include "textout.h" // Прототип функции окна приложения MRESULT EXPENTRY WndProc(HWND, ULONG, MPARAM, MPARAM); // ================================================= // Глобальные переменные // ================================================= HAB hab; HWND hWndFrame; HWND hWndClient; CHAR szAppTitle[] = "TextOut Application"; // ================================================= // Главная функция приложения main // ================================================= int main () { HMQ hmq; QMSG qmsg; BOOL fRc; // Флаги для создания окна Frame Window ULONG flFrameFlags = FCF_SYSMENU | FCF_TITLEBAR | FCF_MINMAX | FCF_SIZEBORDER | FCF_SHELLPOSITION | FCF_TASKLIST | FCF_ICON; // Имя класса главного окна CHAR szWndClass[] = "TEXTOUT"; hab = WinInitialize (0); if(hab == NULLHANDLE) { WinMessageBox (HWND_DESKTOP, HWND_DESKTOP, "Ошибка инициализации", "Ошибка", 0, MB_ICONHAND | MB_OK); return(-1); } // Создаем очередь сообщений hmq = WinCreateMsgQueue (hab, 0); if(hmq == NULLHANDLE) { WinMessageBox (HWND_DESKTOP, HWND_DESKTOP, "Ошибка при создании очереди сообщений", "Ошибка", 0, MB_ICONHAND | MB_OK); WinTerminate (hab); return(-1); } // Регистрация главного окна приложения fRc = WinRegisterClass (hab, szWndClass, (PFNWP)WndProc, 0, 0); if(fRc == FALSE) { WinMessageBox (HWND_DESKTOP, HWND_DESKTOP, "Ошибка при регистрации класса главного окна", "Ошибка", 0, MB_ICONHAND | MB_OK); WinDestroyMsgQueue (hmq); WinTerminate (hab); return(-1); } // Создаем главное окно приложения hWndFrame = WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE , &flFrameFlags, szWndClass, szAppTitle, 0, 0, ID_APP_FRAMEWND, &hWndClient); if(hWndFrame == NULLHANDLE) { WinMessageBox (HWND_DESKTOP, HWND_DESKTOP, "Ошибка при создании главного окна", "Ошибка", 0, MB_ICONHAND | MB_OK); WinDestroyMsgQueue (hmq); WinTerminate (hab); return(-1); } while(WinGetMsg (hab, &qmsg, 0, 0, 0)) WinDispatchMsg (hab, &qmsg); WinDestroyWindow(hWndFrame); WinDestroyMsgQueue (hmq); WinTerminate (hab); return(0); } // ================================================= // Функция главного окна приложения // ================================================= MRESULT EXPENTRY WndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) { CHAR szMsg[100]; int nMsgSize; HPS hps; POINTL ptl; RECTL rec; switch (msg) { // В ответ на это сообщение рисуем в // окне Client Window case WM_PAINT : { // Получаем пространство отображения hps = WinBeginPaint (hWnd, NULLHANDLE, &rec); // Закрашиваем область, требующую обновления WinFillRect (hps, &rec, CLR_WHITE); // Рисуем текстовую строку, начиная с точки, // имеющей координаты (10, 10) ptl.x = 10L; ptl.y = 10L; GpiCharString At (hps, &ptl, 10, "Hello, PM!"); // Освобождаем пространство отображения WinEndPaint (hps); return 0; } // Позволяем окну Frame Window стереть содержимое // окна Client Window case WM_ERASEBACKGROUND : return(MRFROMLONG(1L)); // При изменении размеров окна приложения // перерисовываем его содержимое case WM_SIZE : { WinInvalidateRect (hWnd, NULL, TRUE); return 0; } // Если пользователь сделал щелчок левой клавишей // мыши в окне приложения, в месте расположения // курсора мыши отображаем координаты этого курсора case WM_BUTTON1DOWN : { // Получаем пространство отображения hps = WinGetPS (hWnd); // Определяем координаты курсора мыши и // записываем их в виде текстовой строки // во временный буфер sprintf (szMsg, "(x, y) = (%ld, %ld)", SHORT1FROMMP (mp1), SHORT2FROMMP (mp1)); // Определяем координаты точки для вывода текста ptl.x = SHORT1FROMMP (mp1); ptl.y = SHORT2FROMMP (mp1); // Определяем размер текстовой строки nMsgSize = strlen(szMsg); // Рисуем текстовую строку GpiCharString At (hps, &ptl, nMsgSize, szMsg); // Освобождаем пространство отображения WinReleasePS (hps); return 0; } default: return(WinDefWindowProc (hWnd, msg, mp1, mp2)); } } Функция окна приложения WndProcНаше приложение рисует текстовую строку во время обработки сообщения WM_PAINT , а также во время обработки сообщения WM_BUTTON1DOWN . Кроме того, функция окна обрабатывает сообщение WM_SIZE , поступающее в функцию окна при изменении его размеров. Обработчик сообщения WM_PAINTОбработчик сообщения WM_PAINT получает пространство отображения с помощью функции WinBeginPaint , освобождая его после рисования при помощи функции WinEndPaint . В качестве последнего параметра функции WinBeginPaint передается адрес структуры rec. Функция запишет в нее координаты прямоугольной области, в пределах которой будет выполняться рисование. Сразу после получения пространства отображения обработчик сообщения WM_PAINT закрашивает область белым цветом, вызывая для этого функцию WinFillRect : WinFillRect (hps, &rec, CLR_WHITE ); После этого в окне Client Window рисуется строка текста, для чего вызывается функция GpiCharString At . Обработчик сообщения WM_SIZEСообщения WM_SIZE поступает в функцию окна, когда пользователь изменяет его размеры, например, при помощи мыши. Параметры этого сообщения содержат старые и новые размеры окна, однако в нашем приложении они не используются. В ответ на сообщение WM_SIZE прилоежние TEXTOUT вызывает функцию WinInvalidateRect , как это показано ниже: WinInvalidateRect (hWnd, NULL, TRUE); Функция WinInvalidateRect объявляет, что область внутри окна hWnd требует перерисовки, для чего в очередь приложения помещается сообщение WM_PAINT . При получении пространства отображения функцией WinBeginPaint в структуру rec будет записаны границы этой области. Прототип функции WinInvalidateRect приведен ниже: BOOL WinInvalidateRect ( HWND hwnd, // идентификатор обновляемого окна PRECTL pwrc, // обновляемая область BOOL fIncludeChildren); // дополнительный признак Через параметр hwnd передается идентификатор окна, область внутри которого необходимо обновить. Границы обновляемой области задаются параметром pwrc. Если вместо указателя на структуру типа RECTL указано значение NULL, обновляется все окно. Если значение параметра fIncludeChildren равно TRUE, дополнительно обновляются также все дочерние окна, функциям которых также будет передано сообщение WM_PAINT . Если же значение этого параметра равно FALSE, дочерние окна не будут перерисованы, если родительское окно имеет стиль WS_CLIPCHILDREN . В случае успеха функция WinInvalidateRect возвращает значение TRUE, при ошибке - FALSE. В нашем приложении обработчик сообщения WM_SIZE инициирует перерисовку всего окна Client Window , поэтому при любом изменении размеров главного окна приложения функция окна получит сообщение WM_PAINT . Обработчик этого сообщения вначале сотрет текущее содержимое окна, а затем нарисует текстовую строку Hello, PM! в точке с заданными координатами. Обработчик сообщения WM_ERASEBACKGROUNDСообщение WM_ERASEBACKGROUND посылается окном Frame Window перед тем, как оно будет рисовать окно Client Window . Если обработчик этого сообщения вернет значение TRUE, содержимое окна Client Window будет стерто (точнее говоря, закрашено системным цветом, выбранным для закрашивания внутренней области окна). Если же обработчик сообщения WM_ERASEBACKGROUND вернет значение FALSE, предполагается, что этот обработчик выполнит закрашивание внутренней области окна Frame Window самостоятельно. Именно такая обработка сообщения WM_ERASEBACKGROUND выполняется по умолчанию функцией WinDefWindowProc . Заметим, что вместе с этим сообщением в первом параметре mp1 передается идентификатор пространства отображения для окна Frame Window . Этот идентификатор не следует использовать для закраски окна Client Window , так как сообщение WM_ERASEBACKGROUND передается только в том случае, если необходимо перерисовать окно Frame Window. Может возникнуть такая ситуация, когда содержимое окна Client Window оказалось испорченным, например, в результате размещения там другого окна, а окно Frame Window не изменилось. В этом случае сообщение WM_ERASEBACKGROUND не будет записано в очередь приложения. Поэтому для закрашивания окна Client Window мы использовали обработчик сообщения WM_PAINT . Обработчик сообщения WM_BUTTON1DOWNКогда пользователь делает щелчок левой клавишей мыши в области окна Client Window , функции окна передается сообщение WM_BUTTON1DOWN . В ответ на это сообщение она получает пространство отображения и рисует в месте расположения курсора мыши текстовую строку с координатами курсора. Так как пространство отображения получается не во время обработки сообщения WM_PAINT , вместо функции WinBeginPaint используется функция WinGetPS . После выполнения рисования пространство отображения освобождается функцией WinReleasePS . Файл textout.hВ файле textout.h (листинг 4.2) определена константа ID_APP_FRAMEWND, которая используется при создании главного окна приложения. Листинг 4.2. Файл textout\textout.h #define ID_APP_FRAMEWND 1 Файл textout.rcВ файле описания ресурсов textout.rc (листинг 4.3) определена только пиктограмма приложения. Листинг 4.3. Файл textout\textout.rc #include <os2.h> #include "textout.h" ICON ID_APP_FRAMEWND TEXTOUT.ICO Файл textout.defФайл определения модуля textout.def приведен в листинге 4.4. Листинг 4.4. Файл textout\textout.def NAME TEXTOUT WINDOWAPI DESCRIPTION 'TextOut Application (C) Frolov A., 1996' HEAPSIZE 4096 STACKSIZE 32768 EXPORTS WndProc |