Шрифты и строки
Цель лекции: Дать базовые представления о работе с текстом в 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)