Опубликован: 13.07.2012 | Доступ: свободный | Студентов: 460 / 8 | Оценка: 5.00 / 5.00 | Длительность: 18:06:00
Специальности: Программист
Лекция 6:

Шрифты и строки

< Лекция 5 || Лекция 6: 1234 || Лекция 7 >

Названия гарнитур системных шрифтов мы получаем с помощью метода static const StringArray Font::findAllTypefaceNames(), который возвращает массив строк (класс StringArray Juce), содержащий эти названия. Число элементов массива возвращается его методом int StringArray::size() const throw(). В цикле

for(int i = 0; i < sSystemFonts.size(); i++)
{
    pFontsBox->addItem(sSystemFonts[i], i + 1);
} 

мы перебираем по одному элементы списка и добавляем их в качестве элементов выпадающего списка pFontsBox.

Элементы списка размера шрифтов(pFontSizeBox) добавляем в диапазоне от 8 до 20 пунктов.

Заметим, что в Juce групповой блок служит исключительно в качестве элемента оформления; радиокнопки, рисуемые на его поверхности, не являются его потомками, а представляют собой самостоятельные виджеты. Для того, чтобы объединить их в одну группу, необходимо воспользоваться методом void Button::setRadioGroupId(int newGroupId). Если метод у нескольких радиокнопок принимает в качестве параметра какое-либо одно, отличное от нуля, число, то эти кнопки начинают действовать как единая радиогруппа, т.е. возможно включение одной и только одной кнопки из набора. В качестве ID для нашей радиогруппы используется число 1234.

Деструктор и методы перерисовки и задания размеров нашего класса приведены в листинге 6.3 .

TCentralComponent::~TCentralComponent()
{
  // Удаляем дочерние виджеты
  // и обнуляем их указатели
  deleteAllChildren();
}
//-------------------------------------------------
void TCentralComponent::paint(Graphics& Canvas)
{
  Canvas.fillAll(Colours::azure);
}
//-------------------------------------------------
void TCentralComponent::resized()
{
  pFontViewer->setBounds(proportionOfWidth(0.5505f), 8,    
            proportionOfWidth(0.4192f), 
            proportionOfHeight(0.9507f));
  pFontNameLabel->setBounds(8, 8,       
            roundFloatToInt((proportionOfWidth(0.4192f)) *  
            1.2048f), 25);
  pFontsBox->setBounds(8, 38, 
            roundFloatToInt((proportionOfWidth(0.4192f)) * 
            1.2048f), 25);
  pFontSizeLabel->setBounds (8, 68, 
            roundFloatToInt((proportionOfWidth(0.4192f)) * 
            1.2048f), 25);
  pFontSizeBox->setBounds(8, 96, 
            roundFloatToInt((proportionOfWidth(0.4192f)) * 
            1.2048f), 25);
  pFontStyleLabel->setBounds(8, 126, 
             roundFloatToInt((proportionOfWidth(0.4192f)) * 
             1.2048f), 25);
  pFontGroup->setBounds(8, 156, 
             roundFloatToInt((proportionOfWidth(0.4192f)) * 
             1.2048f), 196);
  pNormalButton->setBounds(32, 185, 150, 25);
  pBoldButton->setBounds(32, 216, 150, 25);
  pItalicButton->setBounds(32, 248, 150, 25);
}
Листинг 6.3. Деструктор и методы paint и resize класса TCentralComponent (файл TCentralComponent.cpp

Для задания относительных горизонтальных размеров виджетов мы использовали уже знакомую функцию int Component::proportionOfWidth(float proportion) const throw(). Для преобразования чисел с плавающей точкой, получаемых после расчёта координат компонентов, в целые использована функция из juce_MathsFunctions.h int roundFloatToInt(const float value) throw().

Как видно из рисунка 6.1 , гарнитура и размер шрифта текста, отображаемого в многострочном текстовом поле TextEditor* pFontViewer, выбираются пользователем из выпадающих списков. Поскольку сам компонент-контейнер TCentralComponent является слушателем изменений списков (ComboBoxListener), в его классе мы переопределяем наследуемую от класса linstener'а виртуальную функцию virtual void ComboBox::Listener::ComboBoxChanged(ComboBox* ComboNoxThatHasChanged), которая отвечает за реакцию программы на выбор пользователя. Её реализация приведена в листинге 6.4 .

void TCentralComponent::comboBoxChanged(ComboBox* pComboBox)
{
  // Изменён выпадающий список гарнитуры шрифта
  if(pComboBox == pFontsBox)
  {
    // Устанавливаем в качестве шрифта текста поля ввода
    // шрифт, выбранный пользователем из списка
    CurrentFont.setTypefaceName(pFontsBox->getText());
  }
  // Изменён выпадающий список размера шрифта
  else if(pComboBox == pFontSizeBox)
  {
    // Вычисляем размер шрифта в пикселях,
    // исходя из выбранного пользователем кегля в типографских пунктах
    float fFontHeight = pFontSizeBox->getText().getFloatValue() * 96 
    / 72;
    // Устанавливаем размер шрифта
    CurrentFont.setHeight(fFontHeight);
  }
  // Задаём шрифт для отображения текста
  pFontViewer->applyFontToAllText(CurrentFont);
}
Листинг 6.4. Реализация функции void ComboBoxChanged(ComboBox*) класса компонента содержимого TCentralComponent (файл TCentralComponent.cpp)

После того, как пользователь выбрал какой-либо пункт в выпадающем списке, отображаемый текст виджета изменяется соответственно надписи выбранного пункта. Получить этот текст можно с помощью функции const String ComboBox::getText() const. В случае первого списка (pFontsBox) это будет название выбранной пользователем гарнитуры шрифта.

Это название передаём в качестве параметра в функию void void Font::setTypefaceName(const String& faceName). Как понятно из названия, она устанавливает гарнитуру вызвавшего шрифта (объект класса Font) с названием, соответствующим строке-параметру. Если гарнитура с таким названием не будет найдена (шрифт не установлен на компьютере), то будет использоваться шрифт по умолчанию. В нашем случае такого происходить не должно, т.к. пользователь выбирает из ранее найденных названий шрифтов, установленных в системе.

Во втором выпадающем списке, pFontSizeBox, пользователь выбирает размер (кегль) шрифта в типографских пунктах. Как уже упоминалось, функция const String ComboBox::getText() const возвращает строку текущего текста списка, объект класса String. Для того, чтобы преобразовать строку в текст, достаточно вызвать метод float String::getFloatValue() const throw(), который преобразует строку в число с плавающей точкой. После этого можно рассчитать высоту шрифта в пикселях, исходя из упоминавшейся выше формулы и задать её для используемого шрифта с помощью функции void Font::setHeight(float newHeight) ( пример 6.4

Теперь можно использовать шрифт с заданными пользователем параметрами для отображения текста в многострочном поле ввода pFontViewer. У класса TextEditor есть для этого два метода:

  • void TextEditor::setFont(const Font& newFont), который устанавливает шрифт для вновь добавляемого в поле текста;
  • void TextEditor::applyFontToAllText(const Font& newFont), который применяет параметры шрифта ко всему тексту поля ввода.

Понятно, что в нашем случае подходит именно второй метод ( пример 6.4).

Задать стиль текста в нашей демонстрационной программе пользователь может посредством трёх радиокнопок, которые мы отнесли к одной группе с ID 1234. Это обеспечивает выбор одной и только одной радиокнопки.

В нашей программе мы даём пользователю возможность выбирать три из четырёх возможных стилей: нормальный, полужирный и курсив (подчёркнутый текст мы использовать не будем). Класс Font имеет следующие функции для задания стиля шрифта:

  • void Font::setBold(bool shouldBeBold) — задаёт полужирное начертание шрифта;
  • void Font::setItalic(bool shouldBeItalic) — задаёт курсивное начертание шрифта;
  • void Font::setUnderline(bool shouldBeUnderline) — задаёт подчёркнутое начертание шрифта.

Значение принимаемого параметра, равное true, задаёт соответствующий стиль шрифта, а равное false — его отменяет. Специальной функции для задания нормального стиля шрифта в Juce нет; для того, чтобы шрифт отображался нормальным начертанием, необходимо отменить все остальные стили с помощью вышеприведённых функций.

Для того, чтобы узнать, какой стиль используется шрифтом, в классе Font библиотеки Juce есть следующие методы:

  • bool Font::isBold() const throw();
  • bool Font::isItalic() const throw();
  • bool Font::isUnderlined() const throw().

В том случае, если функция возвращает истину, начертание шрифта является полужирным, курсивным или подчёркнутым, соответственно.

Попробуем применить эти сведения в нашей программе (см. первый вариант реализации функции void TCentralComponent::buttonClicked(Button* pButton) в пример 6.5).

void TCentralComponent::buttonClicked(Button* pButton)
{
  if (pButton == pNormalButton)
  {
    if(CurrentFont.isBold())
    {
      CurrentFont.setBold(false);
    }
    else if(CurrentFont.isItalic())
    {
      CurrentFont.setItalic(false);  
    }
  }
  else if (pButton == pBoldButton)
  {
    if(CurrentFont.isItalic())
    {
      CurrentFont.setItalic(false);
    }
    CurrentFont.setBold(true);
  }
  else if (pButton == pItalicButton)
  {
    if(CurrentFont.isBold())
    {
      CurrentFont.setBold(false);
    }
    CurrentFont.setItalic(true);
  }
  pFontViewer->applyFontToAllText(CurrentFont);
}
Листинг 6.5. Первый вариант реализации функции buttonClicked класса компонента содержимого TCentralComponent

Следует подчеркнуть, что вызов функций задания того или иного стиля, приведённых в листинге 6.5 , не отменяет предыдущий стиль шрифта. Например, при последовательном вызове

CurrentFont.setBold(true);
CurrentFont.setItalic(true);

мы получим полужирный курсив. Поэтому в первом варианте реализации ( пример 6.5) нам приходится отменять предыдущий стиль перед заданием нового. Хотя программа работает в этом виде вполне корректно, код получается излишне громоздким.

Для того, чтобы задать один и только один стиль шрифта, нужно воспользоваться флагами стиля (упоминавшийся выше перечислимый тип FontStyleFlags. Они принимаются в качестве параметра функцией void Font::setStyleFlags(int newFlags), которая меняет стиль вызвавшего шрифта. Комбинация стилей в этой функции задаётся операцией побитового сложения (|).

Перепишем реализацию функции TCentralComponent::buttonClicked(Button* pButton) ( пример 6.6). Код стал значительно компактнее при сохранении функциональности программы.

void TCentralComponent::buttonClicked(Button* pButton)
{
  if (pButton == pNormalButton)
  {
    // Задаём стиль шрифта - нормальный
    CurrentFont.setStyleFlags(Font::plain);
  }
  else if (pButton == pBoldButton)
  {
    // Задаём стиль шрифта - полужирный
    CurrentFont.setStyleFlags(Font::bold);
  }
  else if (pButton == pItalicButton)
  {   
    // Задаём стиль шрифта - курсив
    CurrentFont.setStyleFlags(Font::italic);
  }
  pFontViewer->applyFontToAllText(CurrentFont);
}
Листинг 6.6. Второй вариант реализации функции buttonClicked класса компонента содержимого TCentralComponent (файл TCentralComponent.cpp

Для получения флага стиля того или иного шрифта используется функция int Font::getStyleFlags() const throw().

Завершая описание класса Font библиотеки Juce, следует отметить, что для него доступны операторы присваивания = (копирует один шрифт в другой) и сравнения (== и !=).

< Лекция 5 || Лекция 6: 1234 || Лекция 7 >