Шрифты и строки
Цель лекции: Дать базовые представления о работе с текстом в Juce
Основным способом "общения" компьютерной программы с пользователем является вывод текстовых сообщений (диалоговые окна, надписи на ярлыках, панелях и т.п.). Внешний вид таких сообщений задаётся тем или иным шрифтом.
Масштабируемый шрифт — это рисунок, задающий внешний вид текста и позволяющий без искажений отображать его на экране компьютера и при печати. Функции отображения и печати шрифта берут на себя специальные функции растеризации, которые преобразуют математическое представление шрифта в растровую матрицу.
Для работы со шрифтами в Juce существует специальный класс, Font. Мы уже использовали его в предыдущих лекциях. Объект этого класса передаётся в качестве параметра в метод setFont() различных компонентов (Label, TextEditor, HyperlinkButton и др.). Класс Component метода setFont() не имеет.
Основные свойства компьютерных шрифтов заимствованы из типографского дела. Ими являются следующие:
- Typeface — гарнитура или внешний вид шрифта, определяемый набором символов, имеющих стилистическое единство. Возвращается методом Typeface* Font::getTypeface() const. Если нужно получить не сам объект гарнитуры, а только её название для текущего шрифта (строку), то можно воспользоваться методом const String& Font::getTypefaceName() const throw().
- Высота шрифта в пикселях. Возвращается методом float Font::getHeight() const throw().
- Стиль шрифта: нормальный, полужирный, курсив и подчёркнутый. Класс Font включает нумерованный список enum FontStyleFlags {plain = 0, bold = 1, italic = 2, underlined = 4}, элементы которого соответствуют вышеперечисленным стилям.
- Если программа Juce не может найти шрифт с заданной комбинацией свойств, то используется другой шрифт, далеко не всегда близкий по свойствам. Поэтому можно воспользоваться методами класса Font для получения названий гарнитур шрифтов, использующихся по умолчанию в данной операционной системе:
- static const String Font::getDefaultMonospacedFontName() — возвращает имя гарнитуры моноширинного рубленного шрифта, используемого по умолчанию;
- static const String Font::getDefaultSerifFontName() — возвращает имя гарнитуры шрифта с засечками (Serif), используемого по умолчанию;
- static const String Font::getDefaultSansSerifFontName() — возвращает имя гарнитуры рубленного шрифта (Sans), используемого по умолчанию.
По умолчанию для всех компонентов Juce задаётся нормальный (стиль plain) шрифт гарнитуры Sans размером 15 пикселей.
В большинстве текстовых редакторов задаётся кегль шрифта — размер высоты символов, измеряемый в типографских пунктах. В Juce высота шрифта, задаваемая методом void Font::setHeight(float newHeight), как упоминалось, измеряется в пикселях. Получить её, исходя из заданного пользователем кегля в типографских пунктах, можно по формуле:
Высота (пиксели) = Кегль (пункты) ? DPI / 72,
где DPI (dots per inch) — число пикселей на дюйм, зависящее от характеристик монитора.
Рассмотрим работу со шрифтами на примере демонстрационного приложения ( рис. 6.1).
В приложении текст из поля ввода (TextEditor* pFontViewer) отображается шрифтом, гарнитура и размер которого выбираются пользователем из выпадающих списков (ComboBox* pFontsBox и ComboBox* pFontSizeBox, соответственно). Стиль шрифта задаётся переключением радокнопок: ToggleButton* pNormalButton — для нормального стиля, ToggleButton* pBoldButton — для полужирного стиля, ToggleButton* pItalicButton — для курсива. Текущий шрифт, используемый для отображения текста в поле ввода, будем сохранять в закрытом члене класса компонента содержимого, Font CurrentFont ( пример 6.1).
#ifndef _TCentralComponent_h_
#define _TCentralComponent_h_
//-------------------------------------------------------
#include "../JuceLibraryCode/JuceHeader.h"
//-------------------------------------------------------
// Класс компонента содержимого.
// Наследует классы слушателей выпадающих списков и кнопок
class TCentralComponent : public Component,
public ComboBoxListener,
public ButtonListener
{
public:
TCentralComponent();
~TCentralComponent();
void paint(Graphics&);
void resized();
// Функция, отслеживающая изменения в выпадающих списках
void comboBoxChanged(ComboBox*);
// Функция, отслеживающая щелчки по кнопке
void buttonClicked(Button*);
private:
// Текущий шрифт текста, отображаемого в TextEditor
Font CurrentFont;
// Многострочное поле ввода
TextEditor* pFontViewer;
Label* pFontNameLabel;
// Выбор гарнитуры шрифта
ComboBox* pFontsBox;
Label* pFontSizeLabel;
// Выбор размера (кегля) шрифта
ComboBox* pFontSizeBox;
Label* pFontStyleLabel;
GroupComponent* pFontGroup;
// Радиокнопка выбора стиля нормального шрифта
ToggleButton* pNormalButton;
// Радиокнопка выбора стиля полужирного шрифта
ToggleButton* pBoldButton;
// Радиокнопка выбора стиля курсива
ToggleButton* pItalicButton;
// Предотвращает создание копии конструктора и оператора =
TCentralComponent(const TCentralComponent&);
const TCentralComponent& operator= (const TCentralComponent&);
};
//----------------------------------------------------
#endif
Листинг
6.1.
Объявление класса компонента содержимого TCentralComponent (файл TCentralComponent.h)
Реализация класса компонента содержимого довольно велика, поэтому рассмотрим её по частям. В конструкторе класса добавим и сделаем видимыми поле ввода, ярлыки, выпадающие списки, групповой блок (GroupComponent* pFontGroup), объединяющий ранее упоминавшиеся радиокнопки ( пример 6.2).
#include "TCentralComponent.h"
//--------------------------------------------------------
#define tr(s) String::fromUTF8(s)
//--------------------------------------------------------
TCentralComponent::TCentralComponent() : Component("Central Component"),
pFontViewer(0),
pFontNameLabel(0),
pFontsBox(0),
pFontSizeLabel(0),
pFontSizeBox(0),
pFontStyleLabel(0),
pFontGroup(0),
pNormalButton(0),
pBoldButton(0),
pItalicButton(0)
{
pFontViewer = new TextEditor("FontViewer");
// Поле ввода - многострочное
pFontViewer->setMultiLine(true);
// Новая строка при нажатии клавиши <ENTER>
pFontViewer->setReturnKeyStartsNewLine(true);
// Запрет на редактирование
pFontViewer->setReadOnly(true);
// Показать полосы прокрутки
pFontViewer->setScrollbarsShown(true);
pFontViewer->setText(tr("Съешь же ещё этих мягких французских булок да выпей чаю.\n1234567890\n`~@#$%^&*()-_=+\\|{[]};:'\"/?"));
addAndMakeVisible(pFontViewer);
pFontNameLabel = new Label("FontNameLabel", tr("Гарнитура (вид) шрифта"));
pFontNameLabel->setFont(Font(15.0000f, Font::plain));
pFontNameLabel->setJustificationType(Justification::centredLeft);
pFontNameLabel->setEditable(false, false, false);
pFontNameLabel->setColour(Label::textColourId, Colours::black);
pFontNameLabel->setColour(Label::backgroundColourId,
Colour(Colours::azure));
addAndMakeVisible(pFontNameLabel);
pFontsBox = new ComboBox("FontsBox");
// Запрет на редактирование текста в выпадающем списке
pFontsBox->setEditableText(false);
// Выравнивание теста по левому краю и центру виджета
pFontsBox->setJustificationType(Justification::centredLeft);
pFontsBox->setTextWhenNothingSelected(tr("Стандартный шрифт"));
// Устанавливаем в качестве слушателя списка
// сам компонент-контейнер
pFontsBox->addListener (this);
addAndMakeVisible(pFontsBox);
// Получаем имена системных шрифтов, сохраняем их
// в строковом массиве...
StringArray sSystemFonts = Font::findAllTypefaceNames();
// и добавляем в выпадающий список
for(int i = 0; i < sSystemFonts.size(); i++)
{
pFontsBox->addItem(sSystemFonts[i], i + 1);
}
pFontSizeLabel = new Label("FontSizeLabel", tr("Размер (кегль) шрифта"));
pFontSizeLabel->setFont(Font(15.0000f, Font::plain));
pFontSizeLabel->setJustificationType(Justification::centredLeft);
pFontSizeLabel->setEditable(false, false, false);
pFontSizeLabel->setColour(Label::textColourId, Colours::black);
pFontSizeLabel->setColour(Label::backgroundColourId,
Colour(Colours::azure));
addAndMakeVisible(pFontSizeLabel);
pFontSizeBox = new ComboBox("FontSizeBox");
pFontSizeBox->setEditableText(false);
pFontSizeBox->setJustificationType(Justification::centredLeft);
pFontSizeBox->setTextWhenNothingSelected(tr("Размер по умолчанию"));
pFontSizeBox->addItem("8", 1);
pFontSizeBox->addItem("9", 2);
pFontSizeBox->addItem("10", 3);
pFontSizeBox->addItem("11", 4);
pFontSizeBox->addItem("12", 5);
pFontSizeBox->addItem("13", 6);
pFontSizeBox->addItem("14", 7);
pFontSizeBox->addItem("15", 8);
pFontSizeBox->addItem("16", 9);
pFontSizeBox->addItem("17", 10);
pFontSizeBox->addItem("18", 11);
pFontSizeBox->addItem("19", 12);
pFontSizeBox->addItem("20", 13);
// Устанавливаем в качестве слушателя списка
// сам компонент-контейнер
pFontSizeBox->addListener (this);
addAndMakeVisible(pFontSizeBox);
pFontStyleLabel = new Label("FontStyleLabel", tr("Стиль шрифта"));
pFontStyleLabel->setFont(Font(15.0000f, Font::plain));
pFontStyleLabel->setJustificationType(Justification::centredLeft);
pFontStyleLabel->setEditable(false, false, false);
pFontStyleLabel->setColour(Label::textColourId, Colours::black);
pFontStyleLabel->setColour(Label::backgroundColourId,
Colour(Colours::azure));
addAndMakeVisible(pFontStyleLabel);
pFontGroup = new GroupComponent("FontGroup", tr("Шрифт"));
pFontGroup->setTextLabelPosition(Justification::centredLeft);
addAndMakeVisible(pFontGroup);
pNormalButton = new ToggleButton("NormalButton");
pNormalButton->setButtonText(tr("Нормальный"));
// Устанавливаем в качестве слушателя кнопки
// сам компонент-контейнер
pNormalButton->addListener(this);
// Радиокнопка отмечена
pNormalButton->setToggleState(true, false);
pNormalButton->setRadioGroupId(1234);
addAndMakeVisible(pNormalButton);
pBoldButton = new ToggleButton("BoldButton");
pBoldButton->setButtonText(tr("Полужирный"));
pBoldButton->addListener(this);
// Радиокнопка не отмечена
pBoldButton->setToggleState(false, false);
pBoldButton->setRadioGroupId(1234);
addAndMakeVisible(pBoldButton);
pItalicButton = new ToggleButton("ItalicButton");
pItalicButton->setButtonText(tr("Курсив"));
pItalicButton->addListener(this);
pItalicButton->setToggleState(false, false);
pItalicButton->setRadioGroupId(1234);
addAndMakeVisible(pItalicButton);
setSize (600, 400);
}
//------------------------------------------------------
Листинг
6.2.
Конструктор класса TCentralComponent (файл TCentralComponent.cpp)
