富文本文档结构
文本文档由QTextDocument 类表示,该类包含有关文档内部表示、结构的信息,并跟踪修改情况,提供撤销/重做功能。
文本文档的结构表示法将其内容显示为文本块、框架、表格和其他对象的层次结构。这些对象为文档提供了逻辑结构,并描述了其内容的显示方式。一般来说,框架和表格用于组合其他结构,而文本块则包含实际的文本信息。
新元素可以通过QTextCursor或编辑器部件(如QTextEdit )以编程方式创建并插入到文档中。创建元素时,可为其指定特定格式;否则,元素将采用光标当前的格式。
![]() | 基本结构 文档 "顶层 "的填充方式如图所示。每个文档总是包含一个根框架,而这个根框架总是包含至少一个文本块。 对于包含一些文本内容的文档,根框架通常包含一系列块和其他元素。 文档中的框架和表格序列总是由文本块分隔,即使文本块不包含任何信息。这样可以确保在现有结构之间插入新元素。 |
在本章中,我们将逐一介绍富文本文档中使用的结构元素,概述它们的特点和用途,并演示如何检查它们的内容。文档编辑将在QTextCursor 接口中介绍。
富文本文档
QTextDocument QTextCursor 对象包含构建富文本文档所需的所有信息。文本文档可以两种互补的方式访问:一种是供编辑使用的线性缓冲区,另一种是对布局引擎有用的对象层次结构。在分层文档模型中,对象一般对应于框架、表格和列表等可视化元素。在较低层次,这些元素描述了文本样式和对齐方式等属性。文档的线性表示法用于编辑和操作文档内容。
虽然QTextEdit 可以方便地显示和编辑富文本,但文档也可以独立于任何编辑器小工具使用:
QTextDocument *newDocument = new QTextDocument;
或者,也可以从现有的编辑器中提取文档:
QTextEdit *editor = new QTextEdit; QTextDocument *editorDocument = editor->document();
这种灵活性使应用程序能够处理多个富文本文档,而无需使用多个编辑器部件,也无需将文档存储为某种中间格式。
空文档包含一个根框架,根框架本身包含一个空文本块。框架提供了文档各部分之间的逻辑分隔,同时也具有决定它们在呈现时如何显示的属性。表格是一种特殊类型的框架,由许多单元格组成,排列成行和列,每个单元格可包含进一步的结构和文本。表格提供了管理和布局功能,允许创建灵活的单元格配置。
文本块包含文本片段,每个片段都指定了文本和字符格式信息。文本属性在字符级和块级都有定义。在字符级,可以指定字体族、文本颜色和字体大小等属性。块级属性可控制更高级别的文本外观和行为,如文本流动方向、对齐方式和背景颜色。
文档结构不能直接操作。编辑是通过基于光标的界面进行的。文本光标界面会自动将新的文档元素插入根框架,并确保在必要时填充空块。
我们通过以下方式获得根框架:
QTextDocument *editorDocument = editor->document(); QTextFrame *root = editorDocument->rootFrame();
当浏览文档结构时,从根框架开始是非常有用的,因为它提供了对整个文档结构的访问。
文档元素
富文本文档通常由段落、框架、表格和列表等常见元素组成。在QTextDocument 中,这些元素由QTextBlock,QTextFrame,QTextTable 和QTextList 类表示。与文档中的其他元素不同,图像是由专门格式化的文本片段表示的。这样,图片就可以与周围的文本以内联方式格式化。
文档的基本结构构件是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 文本块比较: () 和 () 用于测试两个文本块是否相同,而 () 则用于确定哪个文本块在文档中最先出现。operator== operator!= operator<
框架
框架由QTextFrame 类提供。
文本框将文本块和子框架组合在一起,创建比段落更大的文档结构。框架的格式规定了它在页面上的呈现和定位方式。框架可以插入文本流中,也可以浮动在页面的左侧或右侧。每个文档都包含一个根框架,该框架包含所有其他文档元素。因此,除根框架外,所有框架都有一个父框架。
由于文本块用于分隔其他文档元素,因此每个框架总是包含至少一个文本块和零个或多个子框架。我们可以使用QTextFrame::iterator 遍历框架的子元素来检查框架的内容:
QTextFrame::iterator it; for (it = frame->begin(); !(it.atEnd()); ++it) { QTextFrame *childFrame = it.currentFrame(); QTextBlock childBlock = it.currentBlock(); if (childFrame) processFrame(childFrame); else if (childBlock.isValid()) processBlock(childBlock); }
请注意,迭代器会同时选择框架和块,因此有必要检查迭代器所指的是哪一个。这样,我们就可以逐帧浏览文档结构,并在需要时访问文本块。QTextBlock::iterator 和QTextFrame::iterator 这两个类可以互补使用,从文档中提取所需的结构。
表格
表格由QTextTable 类提供。
表格是按行和列排列的单元格集合。每个表格单元格都是一个文档元素,有自己的字符格式,但也可以包含其他元素,如框架和文本块。表格单元格在构建表格或添加额外行或列时自动创建。它们也可以在表格之间移动。
QTextTable 是 的子类,因此在文档结构中,表格被视为框架。对于文档中遇到的每个框架,我们都可以测试它是否代表表格,并以不同的方式处理它:QTextFrame
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(childTable); else processFrame(childFrame); } else if (childBlock.isValid()) { processBlock(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); } }
通过遍历包含图片的文本块中的片段,可以找到表示图片的片段。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.