【Qt之QTextDocument】使用及表格显示富文本解决方案
【Qt之QTextDocument】使用
- 描述
- 常用方法及示例
- 使用QTextList
- 使用QTextBlock
- 使用QTextTable
- 表格显示富文本
- 结论
描述
QTextDocument
类保存格式化的文本。
QTextDocument
是结构化富文本文档的容器,支持样式文本和各种文档元素,如列表、表格、框架和图像。它们可以用于创建QTextEdit
,也可以单独使用。
每个文档元素由一个相关的格式对象描述。每个格式对象都被QTextDocuments
视为唯一的对象,并且可以通过objectForFormat()
传递以获取应用于它的文档元素。
可以使用QTextCursor
以编程方式编辑QTextDocument
,并通过遍历文档结构来检查其内容。整个文档结构都存储在根框架下的文档元素层次结构中,可以使用rootFrame()
函数找到。或者,如果只想迭代文档的文本内容,可以使用begin()
、end()
和findBlock()
检索文本块,以便检查和迭代。
文档的布局由documentLayout()
确定;如果要使用自己的布局逻辑,则可以创建自己的QAbstractTextDocumentLayout
子类,并使用setDocumentLayout()
设置它。可以通过调用metaInformation()
函数获取文档的标题和其他元信息。对于通过QTextEdit
类向用户公开的文档,文档标题也可以通过QTextEdit::documentTitle()
函数获得。
toPlainText()
和toHtml()
便利函数允许以纯文本
和HTML格式
检索文档的内容。可以使用find()
函数搜索文档的文本。
可以使用setUndoRedoEnabled()
函数控制对文档执行的操作的撤消/重做。通过undo()
和redo()
插槽可以控制撤消/重做系统;文档还提供了contentsChanged()
、undoAvailable()
和redoAvailable()
信号,通知连接的编辑器部件有关撤消/重做系统的状态。
以下是QTextDocument
的撤消/重做操作:
- 插入或删除字符。在同一文本块内插入或删除的序列被视为单个撤消/重做操作。
- 插入或删除文本块。在单个操作中的插入或删除序列(例如通过选择然后删除文本)被视为单个撤消/重做操作。
- 文本字符格式更改。
- 文本块格式更改。
- 文本块组格式更改。
常用方法及示例
void addResource(int type, const QUrl &name, const QVariant &resource)
: 添加资源。将资源资源添加到资源缓存中,使用类型和名称作为标识符。type应该是QTextDocument::ResourceType中的值。QVariant resource(int type, const QUrl &name) const
: 获取资源。从具有给定名称的资源返回指定类型的数据。
富文本引擎调用这个函数来请求没有直接存储在QTextDocument中,但仍然与之关联的数据。例如,图像通过QTextImageFormat对象的name属性间接引用。
资源在文档内部缓存。如果在缓存中找不到资源,则调用loadResource来尝试加载该资源。然后loadResource应该使用addResource将资源添加到缓存中。
QTextDocument* doc = ui->textEdit->document();
QImage image(":/images/xxx.png");
doc->addResource(QTextDocument::ImageResource, QUrl("qrc:/images/xxx.png"), QVariant(image));
// 在文档中插入图像
QTextCursor cursor(doc);
cursor.insertImage(doc->resource(QTextDocument::ImageResource, QUrl("qrc:/images/xxx.png")).value<QImage>());
使用addResource()
方法的好处主要包括:
- 方便管理:该方法允许您将资源(如样式表、图像等)添加到文档中,并将其存储在内存中,以便在需要时进行访问。这样可以使资源的管理更加集中和方便。
- 提高效率:通过将资源添加到文档中,您可以在整个文档中重复使用这些资源,而无需每次都从磁盘或网络中加载。这可以减少加载时间,提高应用程序的响应速度。
- 易于维护:使用
addResource()
方法将资源添加到文档中,可以使应用程序的资源管理更加清晰和有序。这使得资源的更新和替换变得更加简单,因为您只需在文档中修改相应的资源即可。 - 支持重用:通过将资源添加到文档中,您可以轻松地在不同的应用程序或文档中使用相同的资源。这有助于减少重复代码,提高代码的可重用性。
- 支持动态内容:
addResource()
方法允许您根据需要动态添加和更新资源。这使得在运行时根据用户交互或其他事件动态更改文档内容变得更加容易。
QTextBlock begin() const
: 返回文档的第一个文本块。QTextBlock end() const
: 该函数返回一个块,用于在迭代文档时测试文档的结尾。返回的块是无效的,并且表示文档中最后一个块之后的块。您可以使用lastBlock()来检索文档的最后一个有效块。
for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next())
qDebug().noquote() << it.text();
QTextBlock firstBlock() const
: 返回文档的第一个文本块内容。QTextBlock lastBlock() const
: 返回文档的最后一个文本块内容。
doc->firstBlock().text();
doc->lastBlock().text();
bool QTextDocument::isEmpty() const
: 如果文档为空,返回true;否则返回false。bool QTextDocument::isRedoAvailable() const
: 如果可重做,则返回true;否则返回false。bool QTextDocument::isUndoAvailable() const
: 如果可撤消,则返回true;否则返回false。QTextBlock QTextDocument::lastBlock() const
: 返回文档的最后一个(有效的)文本块。int QTextDocument::lineCount() const
: 返回此文档的行数(如果布局支持此项)。否则,这与块数相同。
doc->isEmpty();
- 枚举:enum QTextDocument::FindFlag
- 获取枚举值:flags QTextDocument::FindFlags
这个enum
描述QTextDocument
的find
函数可用的选项。这些选项可以从以下列表中进行OR-ed
组合:
常量 | 值 | 描述 | 解释 |
---|---|---|---|
QTextDocument::FindBackward | 0x00001 | Search backwards instead of forwards. | 向后搜索而不是向前搜索。 |
QTextDocument::FindCaseSensitively | 0x00002 | By default find works case insensitive. Specifying this option changes the behaviour to a case sensitive find operation. | 默认情况下,find不区分大小写。指定此选项会将行为更改为区分大小写的查找操作。 |
QTextDocument::FindWholeWords | 0x00004 | Makes find match only complete words. | 使查找只匹配完整的单词。 |
QTextCursor find(const QString &subString, const QTextCursor &cursor, FindFlags options = FindFlags()) const
查找给定字符串subString
在cursor
所代表的文本中的位置,返回一个文本光标,该光标指向找到的文本。如果未找到匹配的字符串,则返回一个空的光标。可以设置查找选项options
,例如大小写敏感、全字匹配等。QTextCursor find(const QString &subString, int position = 0, FindFlags options = FindFlags()) const
查找给定字符串subString
在当前文本中的指定位置position
处开始查找,返回一个文本光标,该光标指向找到的文本。如果未找到匹配的字符串,则返回一个空的光标。可以设置查找选项options
,例如大小写敏感、全字匹配等。QTextCursor find(const QRegExp &expr, int from = 0, FindFlags options = FindFlags()) const
使用正则表达式expr
在当前文本中的指定位置from
处开始查找,返回一个文本光标,该光标指向找到的文本。如果未找到匹配的字符串,则返回一个空的光标。可以设置查找选项options
,例如大小写敏感、全字匹配等。QTextCursor find(const QRegExp &expr, const QTextCursor &cursor, FindFlags options = FindFlags()) const
使用正则表达式expr
在cursor
所代表的文本中的位置查找,返回一个文本光标,该光标指向找到的文本。如果未找到匹配的字符串,则返回一个空的光标。可以设置查找选项options
,例如大小写敏感、全字匹配等。QTextCursor find(const QRegularExpression &expr, int from = 0, FindFlags options = FindFlags()) const
使用正则表达式expr
在当前文本中的指定位置from
处开始查找,返回一个文本光标,该光标指向找到的文本。如果未找到匹配的字符串,则返回一个空的光标。可以设置查找选项options
,例如大小写敏感、全字匹配等。QTextCursor find(const QRegularExpression &expr, const QTextCursor &cursor, FindFlags options = FindFlags()) const
使用正则表达式expr
在cursor
所代表的文本中的位置查找,返回一个文本光标,该光标指向找到的文本。如果未找到匹配的字符串,则返回一个空的光标。可以设置查找选项options
,例如大小写敏感、全字匹配等。
QTextDocument* pDoc = ui->textEdit->document();
pDoc->setPlainText("helloworld");
QTextCursor cursor = ui->textEdit->textCursor();
cursor.insertText("\n");
cursor.insertText("earth");
cursor.insertText("\n");
cursor.insertText("sun");
// 输出查找到的位置,从后往前查找
qDebug() << pDoc->find(QRegularExpression("ear"), cursor.position(), QTextDocument::FindBackward).position();
// 以下查找到会自动选择匹配到的
ui->textEdit->find("ear", QTextDocument::FindBackward);
- 枚举:enum QTextDocument::MetaInformation
这个枚举描述了可以添加到文档中的不同类型的元信息。
常量 | 值 | 描述 | 解释 |
---|---|---|---|
QTextDocument::DocumentTitle | 0 | The title of the document. | 文件的标题。 |
QTextDocument::DocumentUrl | 1 | The url of the document. The loadResource() function uses this url as the base when loading relative resources. | 文档的url。loadResource()函数在加载相关资源时使用此url作为基。 |
- QString metaInformation(MetaInformation info) const
void setMetaInformation(MetaInformation info, const QString &string)
: 将由info指定的类型的文档元信息设置为给定的字符串。
pDoc->setMetaInformation(QTextDocument::DocumentTitle, "helloworld");
qDebug() << pDoc->metaInformation(QTextDocument::DocumentTitle);
23. 获取文本块数目、行数、是否编辑、是否为空等操作
// 文本块数目
qDebug() << pDoc->blockCount();
// 行数
qDebug() << pDoc->lineCount();
// 是否是空
qDebug() << pDoc->isEmpty();
// 是否编辑
qDebug() << pDoc->isModified();
// 是否执行Redo
qDebug() << pDoc->isRedoAvailable();
// 是否执行Undo
qDebug() << pDoc->isUndoAvailable();
// Undo和Redo是否使能
qDebug() << pDoc->isUndoRedoEnabled();
24. void setHtml(const QString &html)
pDoc->setHtml("<p style='color:#ff0000;'>helloworld</p>");
25. void setPlainText(const QString &text)
使用此方法,会将textEdit.setTextColor()方法设置的文本颜色失效。
pDoc->setPlainText("helloworld");
使用QTextList
QTextDocument* pDoc = ui->textEdit->document();
pDoc->setPlainText("helloworld\n");
QTextCursor cursor(pDoc);
QTextListFormat listFormat;
listFormat.setStyle(QTextListFormat::ListDecimal); // 使用有序列表
QTextList * pList = cursor.insertList(listFormat);
cursor.insertText("Item 1\n");
cursor.insertText("Item 2\n");
cursor.insertText("Item 3");
QTextList* list = cursor.currentList();
qDebug() << list->count();
if (list) {
QTextBlock currentItem = list->item(0);
// 处理列表中的第一个项
QString text = currentItem.text();
qDebug() << text;
}
使用QTextBlock
QTextDocument* pDoc = ui->textEdit->document();
QTextCursor cursor(pDoc);
cursor.insertText("\n");
cursor.insertText("Hello, World!");
QTextBlock currentBlock = pDoc->firstBlock();
while (currentBlock.isValid()) {
QString text = currentBlock.text();
// 处理当前段落的文本内容
qDebug() << text;
currentBlock = currentBlock.next();
}
使用QTextTable
QTextDocument* pDoc = ui->textEdit->document();
// pDoc->setPlainText("helloworld\n");
QTextCursor cursor(pDoc);
QTextTableFormat tableFormat;
tableFormat.setBorder(1);
tableFormat.setCellPadding(5);
tableFormat.setAlignment(Qt::AlignCenter);
cursor.insertTable(3, 2, tableFormat);
QTextTable* table = cursor.currentTable();
if (table) {
for (int row = 0; row < table->rows(); ++row) {
for (int col = 0; col < table->columns(); ++col) {
QTextTableCell cell = table->cellAt(row, col);
QTextCursor cellCursor = cell.firstCursorPosition();
cellCursor.insertText(QString("Row %1, Col %2").arg(row).arg(col));
}
}
}
表格显示富文本
QTableWidget
是Qt框架提供的一个用于显示表格数据的控件。然而,QTableWidget
本身并不直接支持富文本(rich text)的显示。如果需要在QTableWidget
中显示富文本,一种方法是使用QTableWidgetItem
的setData
方法,将富文本作为自定义数据存储在表格中,然后在单元格的渲染过程中使用自定义的QStyledItemDelegate
来显示这些数据。
#include <QApplication>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QTextDocument>
#include <QTextCharFormat>
#include <QTextCursor>
#include <QStyledItemDelegate>
class RichTextDelegate : public QStyledItemDelegate {
public:
explicit RichTextDelegate(QTableWidget* pTW){
m_pTW = pTW;
}
public:
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
QTableWidgetItem *item = m_pTW->item(index.row(), index.column());
if (item) {
QTextDocument doc;
doc.setHtml(item->data(Qt::UserRole).toString());
doc.drawContents(painter);
}
}
private:
QTableWidget* m_pTW;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QTableWidget table;
table.setColumnCount(1);
table.setRowCount(3);
table.setItemDelegateForColumn(0, new RichTextDelegate(&table));
// 添加富文本数据到表格中
QTableWidgetItem *item1 = new QTableWidgetItem;
item1->setData(Qt::UserRole, "<h1>标题1</h1><p>段落1</p>");
table.setItem(0, 0, item1);
QTableWidgetItem *item2 = new QTableWidgetItem;
item2->setData(Qt::UserRole, "<h1>标题2</h1><p>段落2</p>");
table.setItem(1, 0, item2);
table.show();
return app.exec();
}
- 创建了一个自定义的
RichTextDelegate
类,继承自QTableWidgetItemDelegate
。 - 在
paint
方法中,检查每个表格项的数据,如果存在自定义的富文本数据(存储在Qt::UserRole
),则使用QTextDocument
来渲染这些数据。 - 将这个自定义委托设置为表格的第一列的代理。
结论
只要未来可期,今天就值得欣喜
。