На этом шаге мы рассмотрим использование стандартного диалогового окна Font (Шрифт).
Существует много приложений Windows, включая программы рисования, электронные таблицы и системы управления базами данных, позволяющих пользователю выбрать шрифты различных размеров и цветов с различными атрибутами: подчеркивание, жирность, курсив и перечеркивание. Эта широко распространенная функция реализуется окном диалога Font системы Windows, которую OWL инкапсулирует в своем классе TChooseFontDialog.
Шрифты представляют собой, пожалуй, самые "хитрые" объекты, которыми должен управлять программист, разрабатывающий приложение Windows. Чтобы выбирать и использовать шрифты, вы должны быть знакомы со структурой LOGFQNT, которая содержит информацию о шрифте, и вы должны знать, как создать новые шрифты, если в этом возникнет необходимость.
В таблице 1 приведены поля структуры LOGFONT.
Поле | Описание |
---|---|
lfHeight | Высота шрифта в логических единицах. |
lfWidth | Ширина шрифта в логических единицах. |
lfEscapement | Угол, под которым рисуется текст. |
lfOrientation | Наклон символа в десятых долях градуса. |
lfWeight | Используется для выбора обычного (400) или жирного (700) текста. |
ifItalic | Ненулевое значение указывает курсив. |
lfUnderline | Ненулевое значение задает шрифт с подчеркиванием. |
lfStrikeout | Ненулевое значение задает перечеркнутый шрифт. |
lfCharSet | Устанавливает тип шрифта. |
lfOutPrecision | Задает точность вывода шрифта. |
lfClipPrecision | Определяет, как отсекаются символы, которые частично оказались за границей допустимой области. |
lfQuality | Качество вывода шрифта. |
lfPitchAndFamily | Шаг и семейство шрифта. |
lfFaceName | Определяет начертание шрифта. |
При использовании окна диалога Font библиотеки OWL вам не нужно знать о том, как работают шрифты. Необходимо только иметь достаточные знания о самих шрифтах, чтобы инициализировать структуру TChooseFontDialog::TData и создавать новый шрифт на основании информации, которую возвратит вам окно диалога. Следующий пример показывает, как это делается.
#include <owl\applicat.h> #include <owl\framewin.h> #include <owl\dc.h> #include <owl\choosefo.h> #include <string.h> #include "pr27_1.rc" //Класс приложения class TApp: public TApplication { public: TApp():TApplication(){} void InitMainWindow(); }; //Класс основного окна class TWndw : public TFrameWindow { public: TWndw(TWindow *parent, const char far *title); ~TWndw(); protected: TFont *font; TColor fontColor; char fontName[81]; void CmChooseFont(); void Paint (TDC &paintDC, BOOL, TRect&); DECLARE_RESPONSE_TABLE (TWndw); }; DEFINE_RESPONSE_TABLE1 (TWndw, TFrameWindow) EV_COMMAND(CM_CHOOSEFONT, CmChooseFont), END_RESPONSE_TABLE; TWndw::TWndw(TWindow *parent, const char far *title): TFrameWindow(parent,title) { // Добавить меню к главному окну. AssignMenu("MENU_1"); // Определить расположение и размеры окна. Attr.X=50; Attr.Y=50; Attr.W=GetSystemMetrics(SM_CXSCREEN)/3; Attr.H=GetSystemMetrics(SM_CXSCREEN)/4; // Инициализировать указатель шрифта, цвет и название. font = 0; fontColor = TColor::Black; strcpy(fontName,"System font"); } // TWndw::~TWndw() // Это деструктор главного окна. TWndw::~TWndw() { // Если объект шрифта существует, удалить его. if (font) delete font; } // TWndw::CmChooseFont() // Эта функция реагирует на команду Choose Font, // отображая диалоговое окно "Шрифт". void TWndw::CmChooseFont() { // Определить массив для сообщения об ошибке. char errorMsg[81]; // Создать объект TData диалогового окна Font. TChooseFontDialog::TData fontData; // Инициализировать объект TData. fontData.Flags = CF_EFFECTS | CF_TTONLY | CF_FORCEFONTEXIST | CF_SCREENFONTS; fontData.Color = fontColor; // Создать диалоговое окно Font. TChooseFontDialog *dialog = new TChooseFontDialog (this, fontData); // Выполнить диалоговое окно Font. int result = dialog->Execute(); // Ответить на кнопку "OK" диалогового окна. if (result == IDOK) { // Удалить старый шрифт, если он существует. if (font) delete font; // Создать новый шрифт по выбору пользователя. font = new TFont(&fontData.LogFont); // Получить цвет и название выбранного шрифта. fontColor = fontData.Color; strcpy(fontName, fontData.LogFont.lfFaceName); // Заставить окно перерисоваться. Invalidate(); } // Если произошла ошибка... else if (fontData.Error != 0) { // Вывести окно сообщений об ошибках. wsprintf(errorMsg,"Ошибка #%ld.", fontData.Error); MessageBox(errorMsg, "Ошибка", MB_OK | MB_ICONEXCLAMATION); } } //TWndw::Paint() // Эта функция переопределяет функцию Paint() из // TWindow и реагирует на сообщение WM_PAINT, которое // Windows посылает окну, если оно должно быть // повторно перерисовано. void TWndw::Paint(TDC &paintDC, BOOL, TRect&) { // Если имеется выбранный шрифт... if (font) // ... поместить его в контекст устройства. paintDC.SelectObject (*font); // Установить цвет шрифта. paintDC.SetTextColor (fontColor); // Вывести название шрифта в окне. paintDC.TextOut(10, 10, fontName); } void TApp::InitMainWindow() { TFrameWindow *wndw= new TWndw(0,"Диалоговое окно \"Выбор шрифта\""); SetMainWindow(wndw); } int OwlMain(int,char *[]) { return TApp().Run(); }
Файл ресурсов:
#ifndef WORKSHOP_INVOKED #include "windows.h" #endif #define CM_EXIT 24310 #define CM_CHOOSEFONT 101 #ifdef RC_INVOKED MENU_1 MENU { POPUP "&File" { MENUITEM "E&xit", CM_EXIT } POPUP "&Font" { MENUITEM "&Choose Font...", CM_CHOOSEFONT } } #endif
После запуска этой программы вы увидите окно, показанное на рисунке 1.
Рис.1. Результат работы приложения
Это окно отображает название текущего выбранного шрифта, которое рисуется выбранным шрифтом. Для изменения шрифта выберите из меню Font команду Choose Font. Когда вы это сделаете, то увидите диалоговое окно Font, как показано на рисунке 2.
Рис.2. Окно выбора шрифта
Вы можете использовать это диалоговое окно не только для выбора начертания шрифта, но также для выбора точечного размера шрифта, цвета и атрибутов. После указания шрифта выберите кнопку ОК для выхода из окна диалога. В рабочей области главного окна появится новый шрифт, как показано на рисунке 3.
Рис.3. Окно с выбранным шрифтом
Класс главного окна примера включает три защищенных члена-данных: font, fontcolor и fontName, которые являются соответственно объектом, цветом и названием текущего шрифта. Программа инициализирует эти поля в конструкторе главного окна, устанавливая указатель шрифта в нуль, цвет шрифта в черный и название шрифта в "System font".
В отличие от предыдущих программ этой главы, оконный класс имеет деструктор:
TWndw::~TWndw() { // Если объект шрифта существует, удалить его. if (font) delete font; }
Деструктор отвечает за удаление объекта текущего выбранного шрифта, если он существует. Это освобождает ресурсы для других Windows-приложений.
Большинство действий программы осуществляется в функциях CmChooseFont() и Paint(). CmChooseFont() реагирует на команду Choose Font из пункта меню Font. Эта функция сначала объявляет объект TChooseFontDialog::TData с именем fontData:
TChooseFontDialog::TData fontData;
Затем инициализирует соответствующие члены-данные объекта fontData:
fontData.Flags = CF_EFFECTS | CF_TTONLY | CF_FORCEFONTEXIST | CF_SCREENFONTS; fontData.Color = fontColor;
Так как эта программа работает только с экранными шрифтами, то единственными элементами, которые необходимо инициализировать, являются Flags и Color. Flags является совокупностью флагов, определяющих, каким образом должно выглядеть и функционировать диалоговое окно. В этом случае флаги указывают, что должен быть включен выбор возможных действий (со шрифтом), должны быть перечислены только шрифты типа TrueType; должна посылаться ошибка, если выбранный шрифт или тип не существуют, и только экранные шрифты должны быть перечислены в списке возможных шрифтов. (Таблица 2 содержит предопределенные константы, которые вы можете использовать для этих флагов.) Color - это цвет шрифта, задаваемый по умолчанию. Он представляет собой тот цвет, который будет автоматически выбираться при появлении окна диалога. CmChooseFont() устанавливает это поле в значение fontСolor, которое является текущим выбранным цветом шрифта.
Поле | Описание |
---|---|
CF_APPLY | Отобразить кнопку Apply (Применить). |
CF_ANSIONLY | Допускает выбор только шрифтов с символами в ANSI-кодах. |
CF_BOTH | Выводить список шрифтов экрана и принтера. |
CF_EFFECTS | Допускает подчеркивание, перечеркивание и цвет. |
CF_FIXEDPITCHONLY | Допускает выбор только шрифтов с фиксированным шагом. |
CF_FORCEFONTEXIST | Выдавать ошибку, если пользователь выбрал несуществующий шрифт или тип. |
CF_INITTOLOGFONTSTRUCT | Установить значения управляющих элементов диалога в соответствии со зачениями в LogFont. |
CF_LIMITSIZE | Установить значения размера шрифта между SizeMin и SizeMax. |
CF_NOSIMULATION | Запрещает имитацию шрифта GDI. |
CF_PRINTERFONTS | Выводить список шрифтов только для принтера. |
CF_SCALABLEONLY | Допускает выбор только масштабируемых шрифтов. |
CF_SCREENFONTS | Выводить список шрифтов только для экрана. |
CF_SHOWHELP | Показывает кнопку "Help" блока диалога. |
CF_TTONLY | Допускает выбор только шрифтов True Type. |
CF_USESTYLE | Использует буфер STYLE для инициализации выбора типа шрифта. |
CF_WYSIWYG | Разрешает использовать только шрифты, доступные как для экрана, так и для принтера. |
Таким образом, структура TChooseColorDialog::TData содержит следующие поля:
После создания и инициализации объекта TData, CmChooseFont() создает диалоговое окно TChooseFontDialog с помощью вызова конструктора класса с двумя аргументами: указателем на родительское окно и ссылкой на объект TChooseFontDialog::TData:
TChooseFontDialog *dialog = new TChooseFontDialog (this, fontData);
Если пользователь завершает диалог по кнопке ОК, это означает, что он выбрал новый шрифт. В этом случае CmChooseFont() удаляет старый шрифт (если он существовал), создает новый объект TFont из члена-данного LogFont объекта TData, получает новый цвет шрифта из элемента Color и копирует имя нового шрифта из члена-данного lfFaceName объекта LogFont:
if (result == IDOK) { // Удалить старый шрифт, если он существует. if (font) delete font; // Создать новый шрифт по выбору пользователя. font = new TFont(&fontData.LogFont); // Получить цвет и название выбранного шрифта. fontColor = fontData.Color; strcpy(fontName, fontData.LogFont.lfFaceName); // Заставить окно перерисоваться. Invalidate(); }
Собрав вместе все данные, необходимые для нового шрифта, CmChooseFont() вызывает Invalidate() для того, чтобы послать в окно сообщение WM_PAINT, которое заставит OWL вызвать функцию Paint() главного окна:
void TWndw::Paint(TDC &paintDC, BOOL, TRect&) { // Если имеется выбранный шрифт... if (font) // ... поместить его в контекст устройства. paintDC.SelectObject (*font); // Установить цвет шрифта. paintDC.SetTextColor (fontColor); // Вывести название шрифта в окне. paintDC.TextOut(10, 10, fontName); }
Paint() сначала проверяет, указывает ли font на объект нового шрифта (помните, что при запуске программы значение font равно нулю). Если новый шрифт существует, Paint() выбирает его в контекст устройства. В любом случае функция вызывает SetTextColor() вместе с fontColor, чтобы установить цвет шрифта, а затем вызывает TextOut() для вывода названия шрифта, используя при этом текущий шрифт.
На следующем шаге мы рассмотрим диалоговые окна Find и Replace.