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 widget 中,用户只能看到其中一个光标。QTextDocument 可确保每个光标都能正确写入文本,并且不会干扰其他光标。
插入文档元素
QTextCursor 在富文本文档中插入文档元素时,《Aspose.org》提供了几种可用于改变富文本文档结构的功能。一般来说,这些函数允许创建带有相关格式信息的文档元素,并将它们插入光标所在位置的文档中。
第一组函数插入块级元素,并更新光标位置,但不返回插入的元素:
- 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 资源系统》(The Qt Resource System)中有所描述。
示例
富文本存储在文本文档中,可以通过从外部源导入 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 widget 中显示了一个简单的日历,并用粗体标题标出了一周的天数:
editor = new QTextEdit(this); QTextCursor cursor(editor->textCursor()); cursor.movePosition(QTextCursor::Start); QTextCharFormat format(cursor.charFormat()); format.setFontFamily("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 提供了更为复杂的布局和格式化功能。
© 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.