How to process & export rich text in Qt
June 20, 2021•445 words
As a freelance Software Engineer, I get the chance to work on a vast set of technologies. For one of my clients, I often need to implement features in a C++ backend using the Qt framework.
If Qt makes lots of things easy with its built-in modules, sometimes it's unexpectedly hard to achieve something you thought would be trivial.
I just had an example of it for rich text processing. So let's dive in and see how you can iterate over rich text in Qt and export text and formatting information in a json.
Exporting rich text from Qt, your options
- Build your own HTML parser to handle the rich text.
- pro: flexible
- con: so flexible you're likely to have bug reports filled every week due to an unexpected input (:
- Use a QTextDocument and its setHtml method.
- pro: handles the HTML processing for you.
- con: requires to be familiar with
QTextDocument
sub-classes.
Dissecting the QTextDocument
class
_Extract from the Qt doc, source: https://doc.qt.io/qt-5/qtextblock.html
In a nutshell:
- The parent entity is the QTextDocument.
- A
QTextDocument
is composed of several QTextBlock - Each
QTextBlock
is a collection of multiple QTextFragment
The tricky part is that formatting options are disseminated among the QTextBlock
and the QTextFragment
classes.
For example, you'll find alignment information (whether the text should be displayed on the left, right, center, or justified) in the format class of the QTextBlock
. To be exact, you'll find this information in the QTextBlockFormat class, accessible from the QTextBlock.blockFormat() method.
On the other hand, if you want to know whether a portion of text is in italics, you'll have to look at the QTextFragment
level. The styling class for the QTexFragment
is the QTextCharFormat, accessible from the QTextFragment.charFormat() method.
C++ code snippet
For iterating over a rich text document and recovering text and formatting options in a json.
QJsonDocument exportRichTextToJson(QString myRichTextToProcess) {
// 1. Make a document out of the rich text to enable programatic access to the document
QTextDocument document;
document.setHtml(myRichTextToProcess);
if (document.isEmpty())
return QJsonObject{};
QJsonObject jsonObject;
QJsonArray fragments;
// 2. Iterate over the documents' blocks
for (QTextBlock block = document.begin(); block != document.end(); block = block.next()) {
QTextBlock::iterator frag;
for (frag = block.begin(); !(frag.atEnd()); ++frag) {
QJsonObject fragment;
// Recover block level formatting options
fragment["alignment"] = getBlockAlignment(block); // custom function, returns `left`, `right`, `center`, or `justify`
QTextFragment currentFragment = frag.fragment();
if (currentFragment.isValid()) {
fragment["text"] = currentFragment.text();
// Recover fragment level formatting options
const auto charFormat = currentFragment.charFormat();
fragment["italics"] = charFormat.fontItalic();
fragment["bold"] = isCharBold(charFormat);
fragment["fontSize"] = charFormat.fontPointSize();
fragments.append(fragment);
}
}
}
jsonObject["fragments"] = fragments;
return jsonObject;
}