Шаг 27.
Библиотека OWL.
Диалоговое окно Font (Шрифт)

    На этом шаге мы рассмотрим использование стандартного диалогового окна Font (Шрифт).

    Существует много приложений Windows, включая программы рисования, электронные таблицы и системы управления базами данных, позволяющих пользователю выбрать шрифты различных размеров и цветов с различными атрибутами: подчеркивание, жирность, курсив и перечеркивание. Эта широко распространенная функция реализуется окном диалога Font системы Windows, которую OWL инкапсулирует в своем классе TChooseFontDialog.

    Шрифты представляют собой, пожалуй, самые "хитрые" объекты, которыми должен управлять программист, разрабатывающий приложение Windows. Чтобы выбирать и использовать шрифты, вы должны быть знакомы со структурой LOGFQNT, которая содержит информацию о шрифте, и вы должны знать, как создать новые шрифты, если в этом возникнет необходимость.

    В таблице 1 приведены поля структуры LOGFONT.

Таблица 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, которое является текущим выбранным цветом шрифта.

Таблица 2. Константы флагов TChooseFontDialog::TData
Поле Описание
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 является намного более сложным, чем может показаться из программы-примера. Эта структура заключает в себе 10 членов-данных. Например, при выборе шрифтов для принтера вы должны установить поле TData.DС в значение DC-дескриптора принтера. Вы должны также использовать члены-данные TData.SizeMin и TData.SizeMax, чтобы обязать пользователя выбирать размеры шрифта внутри определенного диапазона.

    Таким образом, структура 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.




Предыдущий шаг Содержание Следующий шаг