前言
官方文档 Rich Text Processing - Rich Text Document Structure
文本文档由QTextDocument 类表示,该类包含有关文档的内部表示、其结构的信息,并跟踪修改以提供撤消/重做功能。
文本文档的结构化表示形式将其内容呈现为文本块、框架、表格和其他对象的层次结构。它们为文档提供了逻辑结构,并描述了其内容的显示方式。通常,框架和表格用于对其他结构进行分组,而文本块则包含实际的文本信息。
使用QTextCursor或使用编辑器小部件(如 QTextEdit)以编程方式创建和插入到文档中的新元素。元素在创建时可以指定特定格式;否则,它们会采用该元素的游标当前格式。
![]() | 基本结构 : 文档的层次如图所示。 每个文档始终包含一个根框架,并且始终包含至少一个文本块。 根框架通常包含一系列块和其他元素。 框架和表的顺序始终由文档中的文本块分隔,即使文本块不包含任何信息。 |
导航文档结构时,从根框架开始非常有用,因为它提供了对整个文档结构的访问。
富文本文档中的结构元素
富文本文档通常由常见元素组成,如段落、框架、表格和列表。这些由QTextBlock、QTextFrame、QTextTable和 QTextList类在QTextDocument中表示。 与文档中的其他元素不同,图像由特殊格式的文本片段表示。这样,它们可以与周围的文本保持格式。
文档中的基本结构构建基本块是QTextBlock 和 QTextFrame。块本身包含富文本片段(QTextFragment),但这些片段并不直接影响文档的高层结构。
可以组合在一起的其他文档元素的元素通常是QTextObject的子类,并分为两类:将文本块组合在一起的元素是QTextBlockGroup 的子类,将框架和其他元素组合在一起的元素是QTextFrame 的子类。
文本块
文本块由 QTextBlock 类提供。
文本块将具有不同字符格式的文本片段分组在一起,并用于表示文档中的段落。每个块通常包含许多具有不同样式的文本片段。将文本插入到文档中时创建片段,并在编辑文档时添加更多片段。文档拆分、合并和删除片段,以有效地表示块中不同的文本样式。
可以使用QTextBlock :: iterator遍历块的内部结构来检查给定块中的片段:
QTextBlock::iterator it;
for (it = currentBlock.begin(); !(it.atEnd()); ++it) {
QTextFragment currentFragment = it.fragment();
if (currentFragment.isValid())
processFragment(currentFragment);
}
块还用于表示列表项。块可以定义自己的字符格式,其中包含有关块级修饰的信息,例如用于列表项的项目的项目符号点的类型。块本身的格式由QTextBlockFormat 类描述,并描述文本对齐、缩进和背景颜色等属性。
尽管给定文档可能包含复杂的结构,但一旦我们引用了文档中的有效块,我们就可以按编写顺序在每个文本块之间导航:
QTextBlock currentBlock = textDocument->begin();
while (currentBlock.isValid()) {
processBlock(currentBlock);
currentBlock = currentBlock.next();
}
当您只想从文档中提取富文本时,此方法很有用,因为它忽略框架、表和其他类型的结构。
QTextBlock提供了便于操作块的比较运算符:运算符= 、!= 用于测试两个块是否相同,运算符 < 用于确定文档中哪个块先出现。
框架
帧由QTextFrame 类提供。
文本框架将文本块和子框架分组在一起,创建大于段落的文档结构。框架的格式指定如何在页面上呈现和定位框架。框架要么插入到文本流中,要么浮动在页面的左侧或右侧。每个文档都包含一个包含所有其他文档元素的根框架。因此,除根帧外,所有帧都有父帧。
由于文本块用于分隔其他文档元素,因此每个框架将始终包含至少一个文本块和零个或多个子框架。我们可以使用 QTextFrame::iterator 来遍历帧的子元素来检查帧的内容:
QDomElement frameElement = ...
QTextFrame::iterator it;
for (it = frame->begin(); !(it.atEnd()); ++it) {
QTextFrame *childFrame = it.currentFrame();
QTextBlock childBlock = it.currentBlock();
if (childFrame)
processFrame(frameElement, childFrame);
else if (childBlock.isValid())
processBlock(frameElement, childBlock);
}
注意,迭代器会同时选择帧和块,因此有必要检查它所指的是哪个。 这使我们可以逐帧浏览文档结构,但仍可以根据需要访问文本块。 QTextBlock :: iterator和QTextFrame :: iterator类都可以互补使用,以从文档中提取所需的结构。
表
表由QTextTable 类提供。
表是按行和列排列的单元格集合。每个表单元格都是具有其自身字符格式的文档元素,但它也可以包含其他元素,如框架和文本块。在构造表或添加额外的行或列时,将自动创建表单元格。它们也可以在表之间移动。
QTextTable是QTextFrame 的子类,因此表在文档结构中被视为框架。对于我们在文档中遇到的每个帧,我们可以测试它是否表示表,并使用不同的方式处理它:
QDomElement frameElement = ...
QTextFrame::iterator it;
for (it = frame->begin(); !(it.atEnd()); ++it) {
QTextFrame *childFrame = it.currentFrame();
QTextBlock childBlock = it.currentBlock();
if (childFrame) {
QTextTable *childTable = qobject_cast<QTextTable*>(childFrame);
if (childTable)
processTable(frameElement, childTable);
else
processFrame(frameElement, childFrame);
} else if (childBlock.isValid())
processBlock(frameElement, childBlock);
}
可以通过通过对行和列进行流经来检查现有表中的单元格。
for (int row = 0; row < table->rows(); ++row) {
for (int column = 0; column < table->columns(); ++column) {
QTextTableCell tableCell = table->cellAt(row, column);
processTableCell(tableCell);
}
}
列表
列表由QTextList 类提供。
列表是按通常方式格式化的文本块序列,但也提供标准列表修饰,如项目符号点和枚举项。列表可以嵌套,如果列表的格式指定非零缩进,则将缩进。
我们可以按列表中的索引引用每个列表项:
for (int index = 0; index < list->count(); ++index) {
QTextBlock listItem = list->item(index);
processListItem(listItem);
}
由于QTextList是QTextBlockGroup 的子类,因此它不将列表项分组为子元素,而是提供用于管理它们的各种函数。这意味着我们在遍历文档时找到的任何文本块实际上可能是列表项。我们可以通过使用以下代码确保正确标识列表项:
QTextFrame::iterator it;
for (it = frame->begin(); !(it.atEnd()); ++it) {
QTextBlock block = it.currentBlock();
if (block.isValid()) {
QTextList *list = block.textList();
if (list) {
int index = list->itemNumber(block);
processListItem(list, index);
}
}
}
图像
QTextDocument 中的图像由通过资源机制引用外部图像的文本片段表示。图像是使用光标界面创建的,以后可以通过更改图像文本片段的字符格式进行修改:
if (fragment.isValid()) {
QTextImageFormat newImageFormat = fragment.charFormat().toImageFormat();
if (newImageFormat.isValid()) {
newImageFormat.setName(":/images/newimage.png");
QTextCursor helper = cursor;
helper.setPosition(fragment.position());
helper.setPosition(fragment.position() + fragment.length(),
QTextCursor::KeepAnchor);
helper.setCharFormat(newImageFormat);
}
}
通过遍按包含图像的文本块中的片段,可以找到表示图像的片段。
总结
富文本文档通常由常见元素组成,如段落、框架、表格和列表。分别对应于QTextBlock、QTextFrame、QTextTable和 QTextList类在QTextDocument中表示。 与文档中的其他元素不同,图像由特殊格式的文本片段表示。