[Предыдущая: Система рисования Arthur] [Начало] [Следующая: Классы главного окна в Qt 4]
Классы работы с текстом Scribe
Scribe предоставляет набор классов Qt 4 для размещения текста. Эти классы заменяют мощный текстовый движок Qt 3 и предоставляют новые возможности обработки и компоновки простого и форматированного текста.
Для более детального ознакомления с классами Scribe смотрите документ Обработка форматированного текста.
Обзор Scribe
Поддержка отображения и компоновки текста в Qt 4 была перепроектирована с использованием системы, позволяющей осуществлять эти действия более гибко, чем в Qt 3. Qt 4 также предоставляет более удобный интерфейс для программирования изменения документов. Эти усовершенствования были достигнуты с помощью переработки системы отрисовки текста и предоставления нескольких новых классов.
Далее следует краткий обзор основных концепций Scribe.
Интерфейс документа
Текстовые документы скорее представлены классом QTextDocument, чем набором объектов QString. Каждый объект QTextDocument содержит информацию о внутреннем представлении документа, его структуре и отслеживает последовательность модификаций для поддержки возможностей отмены/повторения. Данный подход позволяет делегировать управление компоновкой классам-наследникам при сохранении централизованного управления в одном классе.
Документы могут быть конвертированы из внешних источников или созданы на пустом месте с использованием Qt. Создание документа может быть осуществлено с помощью виджета-редактора, такого как QTextEdit, или с помощью вызова API Scribe.
К текстовым документам можно обращаться двумя взаимодополняющими способами: как к линейному буферу (для редактирования и использования) и как к иерархической структуре (для управления компоновкой). В иерархической модели документа объекты, как правило, соответствуют визуальным элементам типа рамок, таблиц и списков. На низовом уровне эти элементы описывают такие атрибуты текста, как стиль и выравнивание. Линейное представление используется для редактирования и манипуляции содержимым документа.
Структура документа
Каждый документ содержит корневую структуру в которую помещены все остальные элементы. Коневая структура содержит такие структурные элементы как таблицы, блоки текста и т.д., которые могут иметь произвольную глубину вложения.
Структура не только представляет логическую организацию документа, но и содержит свойства, влияющие на отрисовку текста. Таблица - это специализированный элемент, состоящий из ячеек, расположенных в виде строк и столбцов и содержащих структуры более низкого уровня или текст. Таблицы обеспечивают управление расположением с помощью создания гибких конфигураций ячеек.
Текстовые блоки содержат сам текст и признаки его форматирования. Свойства текста можно задавать как для символа, так и для блока целиком. На уровне символа могут быть определены такие свойства как начертание и размер шрифта, а также цвет символов. Свойства текстового блока управляют более глобальными особенностями текста, такими как выравнивание текста, его направления и фонового цвета.
Структура документа не имеет непосредственного управления. Управление производится через интерфейс на основе курсоров.
Создание содержимого документа и его редактирование
Документы могут быть отредактированы через интерфейс, предоставленный классом QTextCursor; курсоры создаются с при помощи конструкторов или получают от виджетов-редакторов. Курсор используется для выполнения таких действий по редактированию, которые пользователь осуществляет сам, работая в редакторе. В результате информация о структуре документа также становится доступна и может быть изменена. Использование для редактирования интерфейса ориентированного на курсор делает для разработчиков более простым процесс написания пользовательского редактора, так как операции редактирования могут быть легко визуализированы.
Класс QTextCursor также содержит информацию о выделенном в документе тексте и поддерживает возможности работы с выделенным текстом подобно возможностям работы пользователя в текстовом редакторе.
Компоновка документа
Управление компоновкой уместно лишь когда документ должен быть отображен на некотором устройстве или когда требуются некоторые сведения для визуализации информации о документе. Пока этого не происходит, документ не может быть отформатирован и подготовлен для отображения.
Компоновкой каждого документа управляет подкласс QAbstractTextDocumentLayout. Этот класс предоставляет общий интерфейс для движков компоновки и отображения. По умолчанию процесс отрисовки реализован в частном классе. Такой подход делает возможным создание собственных компоновщиков и предоставляет механизм, используемый при подготовки страниц для печати или экспорта в файлы Portable Document Format (PDF).
Примеры кода
Здесь представлены два способа использования Scribe: для создания и манипулирования форматированным текстом и для размещения простого текста.
Управление форматированным текстом
Форматированный текст хранится в текстовых документах, которые могут быть созданы импортированием HTML из внешних источников или созданы с помощью QTextCursor. Самый легкий способ использования форматированного текстового документа - это использование класса QTextEdit, обеспечивающего отображение и возможность редактирования документа. Код, приведённый ниже, импортирует документ HTML в текстовый документ и отображает текстовый документ в виджете, позволяющем редактировать текст.
QTextEdit *editor = new QTextEdit(parent);
editor->setHtml(aStringContainingHTMLtext);
editor->show();
Вы можете получить указатель на текстовый документ от тестового редактора с помощью функции document(). После этого документ можно изменить программно, используя класс QTextCursor. Этот класс работает по принципу экранного курсора, а операции редактирования отображаются на экране. Следующий код изменяет начертание шрифта первой строки на полужирное, оставляя все другие характеристики нетронутыми. Редактор автоматически обновится для отображения сделанных изменений.
QTextDocument *document = edit->document();
QTextCursor cursor(document);
cursor.movePosition(QTextCursor::Start);
cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
QTextCharFormat format;
format.setFontWeight(QFont::Bold);
cursor.mergeCharFormat(format);
Обратите внимание на то, что курсор был перемещен от начала строки к концу и при этом сохранилась привязка к началу строки. Это показывает средства для работы с классом QTextCursor.
Используя подход на основе курсора, можно очень быстро создать форматированный текст. Следующий пример отображает календарь в виджете QTextEdit с полужирными заголовками дней недели:
editor = new QTextEdit(this);
QTextCursor cursor(editor->textCursor());
cursor.movePosition(QTextCursor::Start);
QTextCharFormat format(cursor.charFormat());
format.setFontFamily("Courier");
QTextCharFormat boldFormat = format;
boldFormat.setFontWeight(QFont::Bold);
cursor.insertBlock();
cursor.insertText(" ", boldFormat);
QDate date = QDate::currentDate();
int year = date.year(), month = date.month();
for (int weekDay = 1; weekDay <= 7; ++weekDay) {
cursor.insertText(QString("%1 ").arg(QDate::shortDayName(weekDay), 3),
boldFormat);
}
cursor.insertBlock();
cursor.insertText(" ", format);
for (int column = 1; column < QDate(year, month, 1).dayOfWeek(); ++column) {
cursor.insertText(" ", format);
}
for (int day = 1; day <= date.daysInMonth(); ++day) {
int weekDay = QDate(year, month, day).dayOfWeek();
if (QDate(year, month, day) == date)
cursor.insertText(QString("%1 ").arg(day, 3), boldFormat);
else
cursor.insertText(QString("%1 ").arg(day, 3), format);
if (weekDay == 7) {
cursor.insertBlock();
cursor.insertText(" ", format);
}
}
Вышеприведенный пример демонстрирует, насколько просто создается форматированный текст и как мало для этого нужно кодировать. Хотя для минимизации кода мы отобразили простой неизменный календарь, Scribe предоставляет возможности более сложной компоновки и форматирования текста.
Выравнивание простого текста
Иногда важно иметь возможность расположения текста в пределах изменяющейся области, например, при отрисовке собственноручно созданного виджета. Scribe предоставляет возможность для обтекания текстом, подобно тому, как это реализовано в QTextLayout, и расположения текста без потребности создания документа с начала.
Отображение простого текста обычно осуществляется вдоль прямых линий. Пример, приведенный ниже, расположит простой текст вдоль внешней кромки правой части круга, используя обычный шрифт.
QTextLayout textLayout(text, font);
qreal margin = 10;
qreal radius = qMin(width()/2.0, height()/2.0) - margin;
QFontMetrics fm(font);
qreal lineHeight = fm.height();
qreal y = 0;
textLayout.beginLayout();
while (1) {
QTextLine line = textLayout.createLine();
if (!line.isValid())
break;
qreal x1 = qMax(0.0, pow(pow(radius,2)-pow(radius-y,2), 0.5));
qreal x2 = qMax(0.0, pow(pow(radius,2)-pow(radius-(y+lineHeight),2), 0.5));
qreal x = qMax(x1, x2) + margin;
qreal lineWidth = (width() - margin) - x;
line.setLineWidth(lineWidth);
line.setPosition(QPointF(x, margin+y));
y += line.height();
}
textLayout.endLayout();
QPainter painter;
painter.begin(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.fillRect(rect(), Qt::white);
painter.setBrush(QBrush(Qt::black));
painter.setPen(QPen(Qt::black));
textLayout.draw(&painter, QPoint(0,0));
painter.setBrush(QBrush(QColor("#a6ce39")));
painter.setPen(QPen(Qt::black));
painter.drawEllipse(QRectF(-radius, margin, 2*radius, 2*radius));
painter.end();
Мы создаем компоновку текста, определяя строку, которую мы хотим показать, и шрифт. Мы добиваемся правильного расположения текста, получая строки текста от объекта форматирования, и располагаем текст в предоставленном пространстве. Строки позиционируются горизонтально и вертикально, поскольку мы смещаемся вниз по странице.
Форматированный текст может быть отображен на устройстве рисования; в вышеприведенном примере форматированный текст отображен на виджете.
Особенности печати
Система компоновки, предназначенная для работы с форматированным текстом, также поддерживает и компоновку документа с разбиением по страницам, что используется Qt для создания заданий для печати. Процедура печати выполняется QPrinter и управляется пользователем через настройки, отображаемые в QPrintDialog:
QTextDocument *document = editor->document();
QPrinter printer;
QPrintDialog *dlg = new QPrintDialog(&printer, this);
if (dlg->exec() != QDialog::Accepted)
return;
document->print(&printer);
Форматированные текстовые документы с помощью QPrinter и соответствующего движка печати могут также экспортироваться как файлы PDF:
QString fileName = QFileDialog::getSaveFileName(this, "Export PDF",
QString(), "*.pdf");
if (!fileName.isEmpty()) {
if (QFileInfo(fileName).suffix().isEmpty())
fileName.append(".pdf");
QPrinter printer(QPrinter::HighResolution);
printer.setOutputFormat(QPrinter::PdfFormat);
printer.setOutputFileName(fileName);
textEdit->document()->print(&printer);
}
Сравнение с Qt 3
Возможности основанного на курсорах редактирования, объединенные со структурной моделью документа, предоставляют мощный набор инструментов для редактирования и отображения форматированного текста. Они обеспечивают возможности, которые были недоступны в открытых API Qt 3. Новый текстовый движок полностью переписан и не использует текстовый движок Qt 3.
Класс QTextEdit в Qt 4 полностью переписан и имеет API, существенно отличный от своего коллеги в Qt 3. Некоторые методы оставлены для совместимости со стилем программирования виджетов, знакомым пользователям Qt 3. Данный класс является полным примером виджета-редактора с новым API, демонстрируя возможности редактирования основанного на интерфейсе редактирования QTextCursor.
[Предыдущая: Система рисования Arthur] [Начало] [Следующая: Классы главного окна в Qt 4]
|