Qt 富文本处理(QTextDocument和QTextBlock和QTextFrame和QTextTable和QTextList和QTextDocument)
最近使用 Qt 做一个离线博客编辑器,因而用到了 Qt 的富文本处理。参考 Qt 的文档,记录下 Qt 的富文本处理的相关技术。文档地址是 http://doc.qt.nokia.com/4.7/richtext.html,本文不是文档的准确翻译,但是内容和文档是基本一致的。
新版本 Qt 使用 QTextDocument 类作为富文本处理的中心类。相比之下,老版本则是使用基于文本的标记语言。
现在,Qt 操作文档的接口可以分成两类:基于光标的接口(cursor-based interface)用于编辑,只读的层次接口(read-only hierarchical interface)用于提供文档结构的概览。基于光标的编辑的主要优点是,能够自然地模拟用户使用编辑器进行编辑的过程,不会丢失文档的底层结构;而只读的层次接口则有利于对于文档检索和导出。
富文本文档结构
富文本文档由 QTextDocument 类描述。这个类包含了文档的内部表示、结构,并且内置了 redo/undo 等操作的支持。
文档的结构化表示描述了它包含的文本块(text block)、框架(frame)、表格(table)以及其他元素的层次化信息。这提供了文档的逻辑结构以及展现其内容的方式。一般的,框架和表格用于组织其他结构,而文本块则包含真正的文本信息。
新元素的创建和插入可以通过使用 QTextCursor 以编程的方式实现,或者通过 QTextEdit 以用户可视化编辑的方式实现。元素可以在创建时指定一个特定的样式,或者是直接使用当前光标所在位置的样式。
下图给出了文档结构的示例。

文档的基本结构是:文档的“顶层”决定显示的方式布局。每一个文档都包括一个根框架(root frame),以及至少一个文本块。对于含有多种文本内容的文档,根框架通常会包含一系列的块和其他元素。在文档中,框架和表格的顺序由文本块分隔开。有时候这些文本块根本没有内容。这保证了新元素总是能够插进原有结构之间。
富文本文档
QTextDocument 类包含了富文本文档的所有信息。前面说过,文档可以用两种方式访问:方便编辑器使用的线性缓存(linear buffer)和方便布局引擎使用的对象层次(object hierarchy)。在层次化文档模型中,对象用来描述可视元素,如框架、表格和列表。在更低的层次上,这些元素都有自己的描述属性,如文本风格和对齐方式。文档的线性描述则用于编辑和维护文档内容。
虽然 QTextEdit 提供了方便的富文本显示和编辑的功能,但文档也可以脱离任何一种编辑组件独立使用。例如:
- QTextDocument *newDocument = new QTextDocument;
另外,也可以通过已有的文本组件获得:
- QTextEdit *editor = new QTextEdit;
- QTextDocument *editorDocument = editor->document();
这种灵活性使得应用程序能够同时操作多个文档,而不必包含多个文档组件,也不比要求文档必须存储为某种中间格式。
一个空的文档包含一个根框架,这个框架包含一个空的文本块。框架提供不同文档部分的逻辑分割,同时也提供了在渲染时如何显示的属性。一个表格就是一个特化的框架,包含分布在不同行和列的多个单元。每个单元都能够包含更多的结构和文本。表格提供了灵活配置单元的管理和布局的特性。
文本块包含文本片段。每一个文本片段都有特定的文本和字符格式信息。文本属性在字符级别和块级别定义。在字符级别可以指定字体、颜色和大小。在块级别可以指定更高一级的行为,例如文本流方向、对齐方式和背景色。
文档结构并不是直接维护的,而是需要通过基于光标的接口进行编辑。文档光标接口会自动向根框架插入新的文档元素,并且确保这个元素在必要时有一个适合的空块。
我们可以通过以下方式访问到根框架:
- QTextDocument *textDocument;
- QTextFrame *root = textDocument->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(frameElement, childFrame);
- else if (childBlock.isValid())
- processBlock(frameElement, 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(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 中,图像当做一个文本片段,这个文本通过 Qt 资源机制指向图片的外部链接。图像通过光标接口创建,通过改变图像文本片段的样式进行修改:
- 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);
- }
- }
表示图像的片段可以通过遍历包含图像的文本块的所有片段获得。
http://devbean.blog.51cto.com/448512/442632
http://devbean.blog.51cto.com/448512/447358
Qt 富文本处理(QTextDocument和QTextBlock和QTextFrame和QTextTable和QTextList和QTextDocument)的更多相关文章
- Qt富文本编辑器QTextDocument
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt富文本编辑器QTextDocument 本文地址:https://www.tech ...
- Qt 富文本处理
富文本处理 所有的类围绕 QTextDocument 展开, 它保证了用户可以创建和修改 富文本块, 而无须定义中间语言.一个 QTextDocument 可以通过两个接口操作, 一个是用于编辑的 C ...
- PyQt(Python+Qt)学习随笔:富文本编辑器QTextEdit功能详解
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.概述 QTextEdit是一个高级的所见即所得的文档查看器和编辑器 ...
- Qt之QTableView显示富文本
简述 对于QTableView中的显示,我们前面介绍过很多种,其中包括:文本.进度条.复选框等,今天我们介绍一下关于富文本的显示. 可能绝大多数小伙伴会通过QAbstractTableModel中的d ...
- 在线富文本编辑器FckEditor配置(.Net Framework 3.5)
进入FCKeditor文件夹,编辑 fckconfig.js 文件.1.上传设置 . var _FileBrowserLanguage = 'php' ; // a ...
- QTableView使用HTML显示富文本
对于QTableView中的显示,我们前面介绍过很多种,其中包括:文本.进度条.复选框等,今天我们介绍一下关于富文本的显示. 可能绝大多数小伙伴会通过QAbstractTableModel中的data ...
- 富文本编辑器Simditor的简易使用
最近打算自己做一个博客系统,并不打算使用帝国cms或者wordpress之类的做后台管理!自己处于学习阶段也就想把从前台到后台一起谢了.好了,废话不多说了,先来看看富文本编辑器SimDitor,这里是 ...
- 个人网站对xss跨站脚本攻击(重点是富文本编辑器情况)和sql注入攻击的防范
昨天本博客受到了xss跨站脚本注入攻击,3分钟攻陷--其实攻击者进攻的手法很简单,没啥技术含量.只能感叹自己之前竟然完全没防范. 这是数据库里留下的一些记录.最后那人弄了一个无限循环弹出框的脚本,估计 ...
- 图解DevExpress RichEditControl富文本的使用,附源码及官方API
9点半了,刚写到1.2. 该回家了,明天继续写完. 大家还需要什么操作,留言说一下,没有的我明天继续加. 好久没有玩DevExpress了,今天下载了一个玩玩,发现竟然更新到14.2.5了..我去 ...
随机推荐
- MYSQL大小写(由于数据由windows迁移到Linux导致)
今日从sqlserver上迁移了一个数据库到Linux的MySQL中,迁移成功了,但是应用却跑不通,查看日志发现,提示找不到表,我注意到,表名都是存在大小写的,而MySQL中的表名都是小写的.这提醒了 ...
- c# 获取指定目录下的所有文件并显示在网页上
参考文献: FileInfo 的使用 https://msdn.microsoft.com/zh-cn/library/system.io.fileinfo_methods(v=vs.110).as ...
- SQL数据库语句练习题目
一. 设有一数据库,包括四个表:学生表(Student).课程表(Course).成绩表(Score)以及教师信息表(Teacher).四个表的结构分别如表1-1的表(一)~表( ...
- IOS 指纹识别的简单使用
首先导入LocalAuthentication框架 然后导入头文件 #import <LocalAuthentication/LAPublicDefines.h> - (void)begi ...
- /etc/group文件详解
Linux /etc/group文件与/etc/passwd和/etc/shadow文件都是有关于系统管理员对用户和用户组管理时相关的文件.linux /etc/group文件是有关于系统管理员对用户 ...
- HTML5 DTD
HTML5/HTML 4.01/XHTML 元素和有效的 DTD 下面的表格列出了所有的 HTML5/HTML 4.01/XHTML 元素,以及它们会出现在什么文档类型 (DTD) 中: 标签 HTM ...
- NAS简介
转自IBM资料库:https://community.emc.com/docs/DOC-15977 在20世纪80年代初,英国纽卡斯尔大学布赖恩.兰德尔教授 ( Brian Randell)和同事通过 ...
- VIM用法
突然感觉vim像是linux上默认的文本编辑器,所以熟悉下用法吧. 1,set nu 显示行号. 2, /word 搜索文本word,n查找下一个. :set hlsearch--高亮显示搜索 ...
- 从零开始学C++之IO流类库(四):输出流格式化(以操纵子方式格式化 以ios类成员函数方式格式化)
一.以操纵子方式格式化 数据输入输出的格式控制使用系统头文件<iomanip>中提供的操纵符.把它们作为插入操作符<<的输出对象即可.如setiosflags.setw.set ...
- MYSQL - php 使用 localhost 无法连接数据库
php 使用 localhost 无法连接数据库,而使用127.0.0.1却能连接成功. 可能原因: 系统hosts文件未提供127.0.0.1到localhost的解析.解决方法(以win7系统为例 ...