QTextCursor 接口
可以通过QTextCursor 类提供的接口对文档进行编辑;光标既可以通过构造函数创建,也可以从编辑器控件中获取。光标用于执行与用户在编辑器中亲自操作完全对应的编辑操作。 因此,通过光标也可获取文档结构的相关信息,从而能够修改该结构。采用基于光标的编辑接口,能让开发人员更轻松地编写自定义编辑器,因为编辑操作可以直观地呈现出来。
QTextCursor 类还会维护文档中已选中文本的相关信息,其模型在概念上同样与用户在编辑器中选择文本的操作相似。
富文本文档可以关联多个光标,每个光标都包含其在文档中的位置信息以及可能持有的任何选定内容。这种基于光标的范式使得诸如剪切和粘贴文本等常见操作在编程上易于实现,同时也能对文档执行更复杂的编辑操作。
本章介绍了您需要使用光标执行的大部分常见编辑操作,从基本的文本和文档元素插入,到更复杂的文档结构操作。
基于光标的编辑
从最简单的层面来看,文本文档由一串字符组成,并通过某种标记方式来表示文档内文本的块结构。QTextCursor 提供了一个基于光标的接口,允许在字符级别上对QTextDocument 的内容进行操作。 由于元素(块、框架、表格等)也编码在字符流中,因此可以通过光标直接更改文档结构。
光标会跟踪其在父文档中的位置,并能报告有关周围结构的信息,例如包围它的文本块、框架、表格或列表。包围结构的格式也可以通过光标直接获取。
使用光标
光标的主要用途是在文本块内插入或修改文本。我们可以使用文本编辑器的光标来完成此操作:
QTextEdit *editor = new QTextEdit();
QTextCursor cursor(editor->textCursor());或者,我们可以直接从文档中获取光标:
QTextDocument *document = new QTextDocument(editor);
QTextCursor cursor(document);光标位于文档开头,以便我们向文档中的第一个(空)块中写入内容。
分组光标操作
可以将一系列编辑操作打包在一起,以便通过单一操作进行重放或撤销。这可以通过以下方式使用beginEditBlock() 和endEditBlock() 函数来实现,如下例所示,其中我们选中了包含光标的单词:
cursor.beginEditBlock();
cursor.movePosition(QTextCursor::StartOfWord);
cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
cursor.endEditBlock();如果未将编辑操作分组,文档会自动记录各项单独操作,以便日后撤销。将操作分组为更大的操作包可以提高用户和应用程序的编辑效率,但需注意不要将过多操作分组在一起,因为用户可能希望对撤销过程进行精细控制。
多光标
可以使用多个光标同时编辑同一文档,尽管在QTextEdit 控件中用户只能看到其中一个。QTextDocument 确保每个光标都能正确写入文本,且不会干扰其他光标。
插入文档元素
QTextCursor 提供了若干函数,可用于更改富文本文档的结构。通常,这些函数允许创建带有相关格式信息的文档元素,并将它们插入到文档的光标位置。
第一组函数用于插入块级元素并更新光标位置,但不会返回所插入的元素:
- insertBlock() 将一个新的文本块(段落)插入文档中的光标位置,并将光标移至新块的开头。
- insertFragment() 将现有的文本片段插入到文档中光标所在位置。
- insertImage() 在文档光标位置插入一张图片。
- insertText() 将文本插入文档中光标所在的位置。
您可以通过光标接口检查所插入元素的内容。
第二组函数用于插入为文档提供结构的元素,并返回所插入的结构:
- insertFrame() 将一个帧插入到文档中光标当前块之后,并将光标移动到新帧中空块的开头。
- insertList() 在文档光标所在位置插入一个列表,并将光标移至该列表中第一个项目的开头。
- insertTable() 在文档中光标当前块之后插入一个框架,并将光标移至该框架内新块的起始位置。
这些元素要么包含文档中的其他元素,要么将其他元素分组在一起。
文本和文本片段
文本可以以当前字符格式插入到当前块中,也可以以随文本指定的自定义格式插入:
cursor.insertText(tr("Character formats"),
headingFormat);
cursor.insertBlock();
cursor.insertText(tr("Text can be displayed in a variety of "
"different character formats. "), plainFormat);
cursor.insertText(tr("We can emphasize text by "));
cursor.insertText(tr("making it italic"), emphasisFormat);一旦某种字符格式与光标关联使用,该格式即成为该光标插入任何文本时的默认格式,直到指定另一种字符格式为止。
如果使用光标插入文本时未指定字符格式,则该文本将采用文档中该位置所使用的字符格式。
块
文本块可通过insertBlock()函数插入到文档中。
QTextBlockFormat backgroundFormat = blockFormat;
backgroundFormat.setBackground(QColor("lightGray"));
cursor.setBlockFormat(backgroundFormat);光标将定位在新块的开头。
框架
帧是通过光标插入到文档中的,并将被放置在光标当前帧内、当前文本块之后。以下代码演示了如何在文档根帧中的两个文本块之间插入一个帧。首先,我们确定光标当前所在的帧:
QTextFrame *mainFrame = cursor.currentFrame();
cursor.insertText(...);我们在该画框中插入一些文本,然后为子画框设置画框格式:
QTextFrameFormat frameFormat;
frameFormat.setMargin(32);
frameFormat.setPadding(8);
frameFormat.setBorder(4);该帧格式将为帧设置 32 像素的外边距、8 像素的内边距以及 4 像素宽的边框。有关帧格式的更多信息,请参阅QTextFrameFormat 文档。
该画框被插入到文档中,位于前面的文本之后:
cursor.insertFrame(frameFormat);
cursor.insertText(...);在插入框架后,我们立即向文档中添加一些文本。由于框架插入文档时文本光标位于框架内部,因此该文本也将插入到框架内。
最后,我们通过采用之前记录的框架内最后一个可用光标位置,将光标定位在框架之外:
cursor = mainFrame->lastCursorPosition();
cursor.insertText(...);最后添加的文本将插入到文档中子画框之后。由于每个画框都用文本块填充,这确保了始终可以通过光标插入更多元素。
表格
表格通过光标插入文档,并将被放置在光标当前帧内、当前文本块之后的位置:
QTextCursor cursor(editor->textCursor());
QTextTable *table = cursor.insertTable(rows, columns, tableFormat);表格可以采用特定格式创建,该格式定义了表格的整体属性,例如对齐方式、背景色以及单元格间距。它还可以确定每列的约束条件,允许每列具有固定宽度,或根据可用空间调整大小。
QTextTableFormat tableFormat;
tableFormat.setBackground(QColor("#e0e0e0"));
QList<QTextLength> constraints;
constraints << QTextLength(QTextLength::PercentageLength, 16);
constraints << QTextLength(QTextLength::PercentageLength, 28);
constraints << QTextLength(QTextLength::PercentageLength, 28);
constraints << QTextLength(QTextLength::PercentageLength, 28);
tableFormat.setColumnWidthConstraints(constraints);
QTextTable *table = cursor.insertTable(rows, columns, tableFormat);上文创建的表格中,各列将分别占据可用宽度的特定百分比。请注意,表格格式是可选的;若插入无格式的表格,系统将采用一些合理的默认值来设置表格属性。
由于单元格可以包含其他文档元素,因此也可以根据需要对其进行格式化和样式设置。
可以通过光标导航至每个单元格并插入文本,将文本添加到表格中。
cell = table->cellAt(0, 0);
cellCursor = cell.firstCursorPosition();
cellCursor.insertText(tr("Week"), charFormat);我们可以按照以下方法创建一个简单的课表:
for (column = 1; column < columns; ++column) {
cell = table->cellAt(0, column);
cellCursor = cell.firstCursorPosition();
cellCursor.insertText(tr("Team %1").arg(column), charFormat);
}
for (row = 1; row < rows; ++row) {
cell = table->cellAt(row, 0);
cellCursor = cell.firstCursorPosition();
cellCursor.insertText(tr("%1").arg(row), charFormat);
for (column = 1; column < columns; ++column) {
if ((row-1) % 3 == column-1) {
cell = table->cellAt(row, column);
QTextCursor cellCursor = cell.firstCursorPosition();
cellCursor.insertText(tr("On duty"), charFormat);
}
}
}列表
可以自动创建块级元素列表,并将其插入到文档中光标当前所在的位置。通过此方式创建的每个列表都需要指定列表格式:
QTextListFormat listFormat;
if (list) {
listFormat = list->format();
listFormat.setIndent(listFormat.indent() + 1);
}
listFormat.setStyle(QTextListFormat::ListDisc);
cursor.insertList(listFormat);上述代码首先检查光标是否位于现有列表内;若是,则会为新列表的列表格式设置适当的缩进级别。这使得能够创建缩进级别逐渐加深的嵌套列表。更复杂的实现还会为列表各级别的项目符号使用不同类型的符号。
图片
内联图片可通过光标以常规方式添加到文档中。与许多其他元素不同,图片的所有属性均由图片格式决定。这意味着在插入图片之前,必须先创建一个 `QTextImageFormat ` 对象:
QTextImageFormat imageFormat;
imageFormat.setName(":/images/advert.png");
cursor.insertImage(imageFormat);图像名称指代应用程序资源文件中的一个条目。关于如何推导该名称的方法,请参阅《Qt 资源系统》。
示例
富文本存储在文本文档中,这些文档既可以通过从外部源导入 HTML 创建,也可以使用 `QTextCursor` 生成。
富文本的操作
使用富文本文档最简单的方法是通过 `QTextEdit ` 类,该类提供了一个可编辑的文档视图。下面的代码将 HTML 导入文档,并使用文本编辑控件显示该文档。
QTextEdit *editor = new QTextEdit(parent);
editor->setHtml(aStringContainingHTMLtext);
editor->show();您可以使用 document() 函数从文本编辑器中获取文档。随后,可通过QTextCursor 类以编程方式编辑该文档。该类以屏幕光标为原型设计,其编辑操作遵循相同的语义规则。以下代码将文档的第一行字体设置为粗体,其余字体属性保持不变。 编辑器将自动更新以反映对底层文档数据所做的更改。
QTextDocument *document = edit->document();
QTextCursor cursor(document);
cursor.movePosition(QTextCursor::Start);
cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
QTextCharFormat format;
format.setFontWeight(QFont::Bold);
cursor.mergeCharFormat(format);请注意,光标已从第一行的开头移动到结尾,但仍在行首保留了一个锚点。这展示了QTextCursor 类的基于光标的选择功能。
生成日历
使用基于光标的方法可以非常快速地生成富文本。以下示例展示了一个简单的日历,该日历位于QTextEdit 控件中,其中各星期几的标题均采用粗体显示:
editor = new QTextEdit(this);
QTextCursor cursor(editor->textCursor());
cursor.movePosition(QTextCursor::Start);
QTextCharFormat format(cursor.charFormat());
format.setFontFamilies({"Courier"});
QTextCharFormat boldFormat = format;
boldFormat.setFontWeight(QFont::Bold);
cursor.insertBlock();
cursor.insertText(" ", boldFormat);
QDate date = QDate::currentDate();
int year = date.year(), month = date.month();
for (int weekDay = 1; weekDay <= 7; ++weekDay) {
cursor.insertText(QString("%1 ").arg(QLocale::system().dayName(weekDay), 3),
boldFormat);
}
cursor.insertBlock();
cursor.insertText(" ", format);
for (int column = 1; column < QDate(year, month, 1).dayOfWeek(); ++column) {
cursor.insertText(" ", format);
}
for (int day = 1; day <= date.daysInMonth(); ++day) {
int weekDay = QDate(year, month, day).dayOfWeek();
if (QDate(year, month, day) == date)
cursor.insertText(QString("%1 ").arg(day, 3), boldFormat);
else
cursor.insertText(QString("%1 ").arg(day, 3), format);
if (weekDay == 7) {
cursor.insertBlock();
cursor.insertText(" ", format);
}
}上述示例展示了如何仅使用最少的代码快速生成新的富文本文档。虽然为了避免引用过多代码,我们生成的是一个粗略的等宽日历,但 Scribe 提供了更为复杂的版面布局和格式设置功能。
© 2026 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.