Приложение 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