Графический интерфейс GDI в Microsoft Windows© Александр Фролов, Григорий ФроловТом 14, М.: Диалог-МИФИ, 1993, 288 стр. 5.3. Приложение FONTVIEWДля того чтобы вы могли быстро попробовать основные функции, предназначенные для выбора шрифта, мы подготовили приложение FONTVIEW. Меню "Font" приложения FONTVIEW позволяет вам выбрать шрифт двумя способами - вы можете указать семейство шрифта или выбрать конкретный шрифт при помощи диалоговой панели "Font". Меню "Orientation" позволяет задать угол поворота текстовой строки, выводя ее с наклоном (рис. 5.3) или даже перевернутой "вверх ногами" (рис. 5.4).
Рис. 5.3. Вывод текста с наклоном С помощью этого приложения вы можете убедиться в том, что повернуть можно только масштабируемые шрифты True Type.
Рис. 5.4. Вывод перевернутого текста Исходный текст приложения приведен в листинге 5.1. Листинг 5.1. Файл fontview/fontview.cpp // ---------------------------------------- // Приложение FONTVIEW // Просмотр шрифтов // ---------------------------------------- #define STRICT #include <windows.h> #include <windowsx.h> #include <commdlg.h> #include <mem.h> #pragma hdrstop #include "fontview.hpp" // Прототипы функций BOOL InitApp(HINSTANCE); LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM); BOOL GetFont(HWND hWnd, LOGFONT *lf, CHOOSEFONT *cf); // Имя класса окна char const szClassName[] = "FontViewClass"; // Заголовок окна char const szWindowTitle[] = "Font Viewer"; // Размеры внутренней области окна short cxClient, cyClient; // Идентификатор копии приложения HINSTANCE hInst; // Строка для вывода char szChars[] = ": AaBbCcDdEeFfGg АаБбВвГгДдЕе"; char szBuf[256]; // Угол наклона строки при выводе int nOrientation = 0; // ===================================== // Функция WinMain // ===================================== #pragma argsused int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; // структура для работы с сообщениями HWND hwnd; // идентификатор главного окна приложения // Инициализируем приложение if(!InitApp(hInstance)) return FALSE; hInst = hInstance; // После успешной инициализации приложения создаем // главное окно приложения hwnd = CreateWindow( szClassName, // имя класса окна szWindowTitle, // заголовок окна WS_OVERLAPPEDWINDOW, // стиль окна CW_USEDEFAULT, // задаем размеры и расположение CW_USEDEFAULT, // окна, принятые по умолчанию CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, NULL); // Если создать окно не удалось, завершаем приложение if(!hwnd) return FALSE; // Рисуем главное окно ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); // Запускаем цикл обработки сообщений while(GetMessage(&msg, 0, 0, 0)) { DispatchMessage(&msg); } return msg.wParam; } // ===================================== // Функция InitApp // Выполняет регистрацию класса окна // ===================================== BOOL InitApp(HINSTANCE hInstance) { ATOM aWndClass; // атом для кода возврата WNDCLASS wc; // структура для регистрации // класса окна // Записываем во все поля структуры нулевые значения memset(&wc, 0, sizeof(wc)); // Подключаем меню wc.lpszMenuName = "APP_MENU"; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszClassName = (LPSTR)szClassName; // Регистрация класса aWndClass = RegisterClass(&wc); return (aWndClass != 0); } // ===================================== // Функция WndProc // ===================================== LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static CHOOSEFONT cf; static LOGFONT lf; static HFONT hfont, hfOldFont;; switch (msg) { // При изменении размеров окна сохраняем // новые значения для ширины и высоты case WM_SIZE: { cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; } // Рисование в окне case WM_PAINT: { // Получаем контекст отображения для // рисования во внутренней области окна hdc = BeginPaint(hwnd, &ps); // Устанавливаем угол наклона строки lf.lfOrientation = lf.lfEscapement = nOrientation; // Создаем шрифт на базе заполненной // структуры LOGFONT hfont = CreateFontIndirect(&lf); if(hfont) { // Выбираем шрифт в контекст отображения hfOldFont = SelectFont(hdc, hfont); // Определяем название шрифта GetTextFace(hdc, 80, szBuf); // Добавляем к нему текстовую строку lstrcat(szBuf, szChars); // Устанавливаем цвет текста SetTextColor(hdc, cf.rgbColors); // Выводим текст, пользуясь выбранным шрифтом TextOut(hdc, cxClient/2, cyClient/2, szBuf, lstrlen(szBuf)); // Выбираем старый шрифт SelectFont(hdc, hfOldFont); // Удаляем созданный нами шрифт DeleteFont(hfont); } // Освобождаем контекст отображения EndPaint(hwnd, &ps); return 0; } // Обработка сообщений от меню case WM_COMMAND: { switch (wParam) { // Выбор шрифта при помощи диалоговой панели case CM_FONTSEL: { // Записываем во все поля структуры типа // LOGFONT нулевые значения memset(&lf, 0, sizeof(LOGFONT)); // Выбираем шрифт if(GetFont(hwnd, &lf, &cf)) { // Перерисовываем окно InvalidateRect(hwnd, NULL, TRUE); } return 0; } // Выбираем шрифт, указывая семейство case CM_FDECOR: { memset(&lf, 0, sizeof(LOGFONT)); lf.lfPitchAndFamily = FF_DECORATIVE; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_FMODERN: { memset(&lf, 0, sizeof(LOGFONT)); lf.lfPitchAndFamily = FF_MODERN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_FROMAN: { memset(&lf, 0, sizeof(LOGFONT)); lf.lfPitchAndFamily = FF_ROMAN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_FSCRIPT: { memset(&lf, 0, sizeof(LOGFONT)); lf.lfPitchAndFamily = FF_SCRIPT; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_FSWISS: { memset(&lf, 0, sizeof(LOGFONT)); lf.lfPitchAndFamily = FF_SWISS; InvalidateRect(hwnd, NULL, TRUE); return 0; } // Выбираем угол поворота строки case CM_FONT00: { nOrientation = 0; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_FONT30: { nOrientation = 300; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_FONT45: { nOrientation = 450; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_FONT90: { nOrientation = 900; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_FONT180: { nOrientation = 1800; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_FONT270: { nOrientation = 2700; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_FONT360: { nOrientation = 3600; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_HELPABOUT: { MessageBox(hwnd, "Font Viewer, v.1.0\n" "(C) Frolov A.V., 1994", "About FONTVIEW", MB_OK | MB_ICONINFORMATION); return 0; } // Завершаем работу приложения case CM_FILEEXIT: { DestroyWindow(hwnd); return 0; } default: return 0; } } case WM_DESTROY: { PostQuitMessage(0); return 0; } default: break; } return DefWindowProc(hwnd, msg, wParam, lParam); } // ===================================== // Функция GetFont // ===================================== BOOL GetFont(HWND hWnd, LOGFONT *lf, CHOOSEFONT *cf) { LPSTR szFontStyle[LF_FACESIZE]; // Записываем нулевые значения во все поля // структуры, которая будет использована для // выбора шрифта memset(cf, 0, sizeof(CHOOSEFONT)); // Размер структуры cf->lStructSize = sizeof(CHOOSEFONT); // Идентификатор окна cf->hwndOwner = hWnd; // Указатель на структуру LOGFONT cf->lpLogFont = lf; // Флаги, определяющие внешний вид диалоговой панели cf->Flags = CF_SCREENFONTS | CF_USESTYLE | CF_EFFECTS; // Дополнительные данные cf->lCustData = 0L; // Цвет текста cf->rgbColors = RGB(0,0,0); // Адрес функции фильтра cf->lpfnHook = (FARPROC)NULL; // Адрес шаблона диалоговой панели cf->lpTemplateName = (LPSTR)NULL; // Идентификатор копии приложения cf->hInstance = hInst; // Стиль шрифта cf->lpszStyle = (LPSTR)szFontStyle; // Тип шрифта cf->nFontType = SCREEN_FONTTYPE; // Ограничения на минимальный и максимальный // размер шрифта cf->nSizeMin = 0; cf->nSizeMax = 0; // Вызываем функцию выбора шрифта return ChooseFont(cf); } Текстовая строка, которая выводится на экран, находится в глобальном массиве szChars. В переменной nOrientation находится текущее значение угла поворота, которое задается при помощи меню "Orientation". Обработчик сообщения WM_PAINT пользуется структурой lf типа LOGFONT, подготовленной при выборе шрифта. Перед созданием шрифта обработчик устанавливает нужный угол наклона строки: lf.lfOrientation = lf.lfEscapement = nOrientation; Затем создается шрифт: hfont = CreateFontIndirect(&lf); Далее шрифт выбирается в контекст отображения, для чего используется макрокоманда SelectFont: hfOldFont = SelectFont(hdc, hfont); Идентификатор шрифта, который был выбран в контекст отображения раньше, сохраняется в переменной hfOldFont. Затем обработчик вызывает функцию GetTextFace, которая копирует в буфер szBuf текстовую строку с названием шрифта, выбранного в контекст отображения. Эта строка затем дописывается ко строке szChars и выводится на экран. Перед выводом устанавливается цвет текста, который берется из заполненной на этапе выбора шрифта структуры CHOOSEFONT: SetTextColor(hdc, cf.rgbColors); Для вывода текста мы используем функцию TextOut, которая была подробно описана в 11 томе "Библиотеки системного программиста". Перед возвратом управления обработчик сообщения WM_PAINT выбирает в контекст отображения старый шрифт и удаляет созданный шрифт: SelectFont(hdc, hfOldFont); DeleteFont(hfont); Когда вы выберите строку "Fonts..." из меню "Font", получит управление обработчик сообщения WM_COMMAND. Он запишет во все поля структуры lf типа LOGFONT нулевые значения и вызовет функцию GetFont, определенную в нашем приложении. После этого он вызовет функцию InvalidateRect для перерисовки окна приложения. Функция GetFont инициализирует нулевыми значениями структуру cf типа CHOOSEFONT, а затем заполняет в этой структуре нужные поля и вызывает функцию ChooseFont: memset(cf, 0, sizeof(CHOOSEFONT)); cf->lStructSize = sizeof(CHOOSEFONT); cf->hwndOwner = hWnd; cf->lpLogFont = lf; cf->Flags = CF_SCREENFONTS | CF_USESTYLE | CF_EFFECTS; cf->lCustData = 0L; cf->rgbColors = RGB(0,0,0); cf->lpfnHook = (FARPROC)NULL; cf->lpTemplateName = (LPSTR)NULL; cf->hInstance = hInst; cf->lpszStyle = (LPSTR)szFontStyle; cf->nFontType = SCREEN_FONTTYPE; cf->nSizeMin = 0; cf->nSizeMax = 0; return ChooseFont(cf); Если вы выбираете из меню "Font" одно из семейств шрифтов, структура lf инициализируется нулевыми значениями, а затем в ней устанавливается поле lfPitchAndFamily: memset(&lf, 0, sizeof(LOGFONT)); lf.lfPitchAndFamily = FF_DECORATIVE; Затем вызывается функция InvalidateRect, что приводит к перерисовке окна приложения. Установка угла наклона выполняется достаточно просто и заключается в изменении значения переменной nOrientation с последующей перерисовкой окна: case CM_FONT30: { nOrientation = 300; InvalidateRect(hwnd, NULL, TRUE); return 0; } Все константы, которые используются для работы с меню, описаны в файле fontview.hpp (листинг 5.2). Листинг 5.2. Файл fontview/fontview.hpp #define CM_HELPABOUT 301 #define CM_FONTSEL 302 #define CM_FILEEXIT 303 #define CM_FONT30 304 #define CM_FONT45 305 #define CM_FONT90 306 #define CM_FONT180 307 #define CM_FONT270 308 #define CM_FONT360 309 #define CM_FONT00 310 #define CM_FDECOR 311 #define CM_FMODERN 312 #define CM_FROMAN 313 #define CM_FSCRIPT 314 #define CM_FSWISS 315 Меню определено в файле ресурсов приложения (листинг 5.3). Листинг 5.3. Файл fontview/fontview.rc #include "fontview.hpp" APP_MENU MENU BEGIN POPUP "&File" BEGIN MENUITEM "E&xit", CM_FILEEXIT END POPUP "F&ont" BEGIN MENUITEM "FF_DECORATIVE", CM_FDECOR MENUITEM "FF_MODERN", CM_FMODERN MENUITEM "FF_ROMAN", CM_FROMAN MENUITEM "FF_SCRIPT", CM_FSCRIPT MENUITEM "FF_SWISS", CM_FSWISS MENUITEM SEPARATOR MENUITEM "&Select Font...",CM_FONTSEL END POPUP "&Orientation" BEGIN MENUITEM "0", CM_FONT00 MENUITEM "30",CM_FONT30 MENUITEM "45",CM_FONT45 MENUITEM "90",CM_FONT90 MENUITEM "180",CM_FONT180 MENUITEM "270",CM_FONT270 MENUITEM "360",CM_FONT360 END POPUP "&Help" BEGIN MENUITEM "&About...", CM_HELPABOUT END END Файл определения модуля приложения FONTVIEW приведен в листинге 5.4. Листинг 5.4. Файл fontview/fontview.def ; ============================= ; Файл определения модуля ; ============================= NAME FONTVIEW DESCRIPTION 'Приложение FONTVIEW, (C) 1994, Frolov A.V.' EXETYPE windows STUB 'winstub.exe' STACKSIZE 8120 HEAPSIZE 1024 CODE preload moveable discardable DATA preload moveable multiple |