На этом шаге мы рассмотрим создание и использование шрифтов при печати вкладыша.
После того, как эскиз вкладыша нарисован, программа должна напечатать текст для названия сторон и названий песен. Так как эти названия используют более мелкий шрифт, чем шрифт для основного названия кассеты, программа не может рассчитывать на шрифты, заданные по умолчанию. Необходимо создать шрифты, которые не только имели бы соответствующие размеры для обеих сторон, но и были бы промасштабированы для текущего принтера. Функция CreateCassFont() выполняет эти задачи:
TFont* TCassPrintout::CreateCassFont(int hSize, int vSize) { LOGFONT cassLogFont; // Описание логического шрифта. // Заполнить структуру LOGFONT. cassLogFont.lfHeight = vSize; cassLogFont.lfWidth = hSize; cassLogFont.lfEscapement = 0; cassLogFont.lfOrientation = 0; cassLogFont.lfWeight = FW_NORMAL; cassLogFont.lfItalic = 0; cassLogFont.lfUnderline = 0; cassLogFont.lfStrikeOut = 0; cassLogFont.lfCharSet = ANSI_CHARSET; cassLogFont.lfOutPrecision = OUT_DEFAULT_PRECIS; cassLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; cassLogFont.lfQuality = PROOF_QUALITY; cassLogFont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN; strcpy(cassLogFont.lfFaceName, "Times New Roman"); // Создать новый шрифт. return new TFont(&cassLogFont); }
Передаваемые этой функции параметры являются горизонтальным и вертикальным размерами шрифта. Чтобы создать шрифт, программа должна инициализировать структуру LOGFONT (логический шрифт), которая содержит полное описание шрифта. В этой структуре имеется 14 полей, большинство из которых, однако, может быть установлено в ноль или значения, заданные по умолчанию в зависимости от требований программы. Вы познакомились со структурой LOGFONT на 27 шаге.
В функции CreateCassFont() программа устанавливает в полях lfHeight и lfWidth структуры LOGFONT высоту и ширину требуемого шрифта. Эти величины являются параметрами, передаваемыми функции. Заметим, что в большинстве случаев лучше установить ширину, равную 0, чтобы позволить Windows выбрать ту ширину, которая лучше сочетается с высотой. В данном же случае, при распечатывании вкладыша для кассеты, вы должны экономить место. Ширина шрифта, выбранная в функции, определит сжатый шрифт, позволяющий программе напечатать более длинные названия песен.
Наконец, в функции CreateCassFont() программа устанавливает многие другие поля LOGFONT в ноль или в значения, заданные по умолчанию, и выбирает семейство шрифтов Roman и начертание Times New Roman. После заполнения структуры LOGFONT программа создает объект TFont и возвращает его указатель вызывающей функции.
Еще кое-что узнать об использовании задаваемого (устанавливаемого) шрифта можно из приведенной ниже функции DrawBodyText():
void TCassPrintout::DrawBodyText(int horDots,int verDots) { TEXTMETRIC metrics;// Описание физического шрифта. char s[80]; // Строка выводимого текста. // Создать и выбрать шрифт для текста кассеты. TFont *newFont = CreateCassFont(horDots/30,verDots/8); DC->SelectObject(*newFont); // Получить размеры физического шрифта. DC->GetTextMetrics(metrics); // Создать и напечатать названия сторон А и В. strcpy(s, "Side А:"); strcpy(&s[strlen(s)], sideAStrgs.sideTitle); DC->TextOut(horDots*0.6, verDots*0.77, s, strlen(s)); strcpy(s, "Side B:"); strcpy(&s[strlen(s)], sideBStrgs.sideTitle); DC->TextOut(horDots*2.6, verDots*0.77, s, strlen(s)); // Напечатать названия песен для сторон А и В. for (int x=0; x<16; ++x) { DC->TextOut((int) (horDots*0.6), (int) (verDots + x*metrics.tmHeight), sideAEdits[x], strlen(sideAEdits[x])); DC->TextOut((int) (horDots*2.6), (int) (verDots + x*metrics.tmHeight), sideBEdits[x], strlen(sideBEdits[x])); } delete newFont; }
Эта функция выводит текст названий песен и названий сторон А и В. Сначала она вызывает CreateCassFont() для создания соответствующих размеров шрифта, масштабируя в соответствии с требованиями приложения значения horDots и verDots. Затем она выбирает новый шрифт в контексте устройства принтера. Так как Windows не всегда может гарантировать, что вы точно получите требуемый шрифт, программа должна проверить характеристики выбранного шрифта. Программа получает их при вызове GetTextMetrics(), заполняющей структуру TEXTMETRICS, указатель на которую является единственным параметром функции. Структура TEXTMETRICS содержит 20 полей для описания выбранного шрифта. Их описание приведено на шаге 20.
В функции DrawBodyText() вы имеете дело только с высотой шрифта, поэтому вы можете определить пространство, отводимое для строки.
После того, как программа вызвала GetTextMetrics(), она создает строки названий для сторон А и В и печатает их на вкладыше. Печать каждой строки производится с помощью вызова функции TextOut() контекста устройства принтера, с масштабированием horDots и verDots, чтобы установить расположение названий. После печати названий сторон программа печатает названия песен, используя цикл for для перебора элементов массива указателей полей ввода (эти указатели были инициализированы в конструкторе объекта печати). Заметьте, как используется поле tmHeight структуры metrics TEXTMETRICS для размещения текста по вертикали. Наконец, функция удаляет шрифт и осуществляет выход.
Теперь, когда эскиз вкладыша для кассеты нарисован, названия сторон и песен напечатаны, осталось только напечатать основное название кассеты. Это выполняется в функции DrawTitleText():
void TCassPrintout::DrawTitleText(int horDots,int verDots) { int strWidth; // Ширина текстовой строки. // Создать новый шрифт названия. TFont *newFont = CreateCassFont(horDots/20, verDots/20); DC->SelectObject(*newFont); // Получить ширину и высоту строки названия. TSize size = DC->GetTextExtent(sideAStrgs.cassTitle, strlen(sideAStrgs.cassTitle)); // Получить ширину строки названия. strWidth = size.cx; // Напечатать основные названия кассеты. DC->TextOut((horDots*2.5)-(strWidth/2),verDots*0.52, sideAStrgs.cassTitle,strlen(sideAStrgs.cassTitle)); DC->TextOut((horDots*2.5)-(strWidth/2),verDots*3.25, sideAStrgs.cassTitle,strlen(sideAStrgs.cassTitle)); delete newFont; }
Здесь программа создает новый, более крупный шрифт для основного названия и выбирает его в контексте устройства. Затем при обращении к GetTextExtent() определяется размер строки названия. Эта функция возвращает объект TSize со значением высоты строки в поле cy, и значением ширины строки - в поле cx. Чтобы центрировать строку названия, программе необходимо знать ширину строки, поэтому strWidth устанавливается в значение size.cx. Используя strWidth, harDots и verDots, масштабированные соответствующим образом, программа вызывает TextOut() для печати на вкладыше центрированного названия. Наконец, программа удаляет новый шрифт.
Таким образом, вкладыш для кассеты пользователя теперь напечатан, и пользователь может выйти из программы, нажав кнопку Cancel или выбрав команду Close из системного меню. Вам не нужно обеспечивать кнопку Cancel функцией отклика на сообщение, так как это сделает за вас библиотека OWL.
Со следующего шага мы начнем рассматривать создание панелей инструментов и строки состояния.