Here we present two different ways in which the Scribe classes can be used: for creating and manipulating rich text, and for laying out plain text.
Manipulating Rich Text
Rich text is stored in text documents that can either be created by importing HTML from an external source, or generated using a QTextCursor. The easiest way to use a rich text document is through the QTextEdit class, providing an editable view onto a document. The code below imports HTML into a document, and displays the document using a text edit widget.
QTextEdit *editor = new QTextEdit(parent);
editor->setHtml(aStringContainingHTMLtext);
editor->show();
You can retrieve the document from the text edit using the document() function. The document can then be edited programmatically using the QTextCursor class. This class is modeled after a screen cursor, and editing operations follow the same semantics. The following code changes the first line of the document to a bold font, leaving all other font properties untouched. The editor will be automatically updated to reflect the changes made to the underlying document data.
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);
Note that the cursor was moved from the start of the first line to the end, but that it retained an anchor at the start of the line. This demonstrates the cursor-based selection facilities of the QTextCursor class.
Rich text can be generated very quickly using the cursor-based approach. The following example shows a simple calendar in a QTextEdit widget with bold headers for the days of the week:
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);
}
}
The above example demonstrates how simple it is to quickly generate new rich text documents using a minimum amount of code. Although we have generated a crude fixed-pitch calendar to avoid quoting too much code, Scribe provides much more sophisticated layout and formatting features.
Plain Text Layout
Sometimes it is important to be able to format plain text within an irregularly-shaped region, perhaps when rendering a custom widget, for example. Scribe provides generic features, such as those provided by the QTextLayout class, to help developers perform word-wrapping and layout tasks without the need to create a document first.
Formatting and drawing a paragraph of plain text is straightforward. The example below will lay out a paragraph of text, using a single font, around the right hand edge of a circle.
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();
We create a text layout, specifying the text string we want to display and the font to use. We ensure that the text we supplied is formatted correctly by obtaining text lines from the text format, and wrapping the remaining text using the available space. The lines are positioned as we move down the page.
The formatted text can be drawn onto a paint device; in the above code, the text is drawn directly onto a widget.
Printing Features
The layout system used to display rich text documents also supports paged layout of documents, and this is used by Qt to generate output for printing. The printing process is performed by QPrinter and controlled by the user via options displayed in a QPrintDialog:
QTextDocument *document = editor->document();
QPrinter printer;
QPrintDialog *dlg = new QPrintDialog(&printer, this);
if (dlg->exec() != QDialog::Accepted)
return;
document->print(&printer);
Rich text documents can also be exported as PDF files using QPrinter and the appropriate print engine:
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);
}
Comparison with Qt 3
The cursor-based editing features, combined with the structural document model, provide a powerful set of tools for manipulating and displaying rich text documents. These provide features that were unavailable in Qt 3's public API. The engine used is a complete rewrite and does not use the rich text engine supplied with Qt 3.
The QTextEdit class in Qt 4 has also been completely rewritten with an API that is quite different from its Qt 3 counterpart. Some compatibility methods have been added to allow the widget to be used, for basic cases, in a way that is familiar to users of Qt 3. This class is provided as a working example of an editor widget that uses the new API, showing that it is possible to completely implement a document editor based on the QTextCursor editing interface.
[Previous: The Arthur Paint System]
[Home]
[Next: The Qt 4 Main Window Classes]