Вывод перевернутого текста
Рис 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