Die QTextCursor-Schnittstelle
Dokumente können über die von der Klasse QTextCursor bereitgestellte Schnittstelle bearbeitet werden; Cursor werden entweder mit einem Konstruktor erstellt oder von einem Editor-Widget bezogen. Der Cursor wird verwendet, um Bearbeitungsoperationen durchzuführen, die genau denen entsprechen, die der Benutzer selbst in einem Editor vornehmen kann. Dadurch stehen über den Cursor auch Informationen über die Dokumentstruktur zur Verfügung, die eine Änderung der Struktur ermöglichen. Die Verwendung einer cursororientierten Schnittstelle für die Bearbeitung macht es für Entwickler einfacher, einen eigenen Editor zu schreiben, da die Bearbeitungsvorgänge leicht visualisiert werden können.
Die Klasse QTextCursor verwaltet auch Informationen über jeden Text, den sie im Dokument ausgewählt hat, und folgt dabei einem Modell, das konzeptionell den Aktionen ähnelt, die der Benutzer zur Auswahl von Text in einem Editor durchführt.
Rich-Text-Dokumenten können mehrere Cursor zugeordnet sein, und jeder dieser Cursor enthält Informationen über seine Position im Dokument und über etwaige Markierungen, die er enthält. Dieses Cursor-basierte Paradigma macht es einfach, gängige Operationen wie Ausschneiden und Einfügen von Text programmatisch zu implementieren, ermöglicht aber auch komplexere Bearbeitungsvorgänge im Dokument.
In diesem Kapitel werden die meisten der üblichen Bearbeitungsvorgänge beschrieben, die Sie mit einem Cursor durchführen müssen, vom einfachen Einfügen von Text und Dokumentelementen bis hin zu komplexeren Manipulationen von Dokumentstrukturen.
Cursorbasierte Bearbeitung
Im einfachsten Fall bestehen Textdokumente aus einer Zeichenkette, die auf irgendeine Weise markiert ist, um die Blockstruktur des Textes innerhalb des Dokuments darzustellen. QTextCursor bietet eine cursorbasierte Schnittstelle, mit der der Inhalt von QTextDocument auf Zeichenebene bearbeitet werden kann. Da die Elemente (Blöcke, Rahmen, Tabellen usw.) ebenfalls im Zeichenstrom kodiert sind, kann die Dokumentstruktur selbst durch den Cursor verändert werden.
Der Cursor verfolgt seine Position innerhalb des übergeordneten Dokuments und kann Informationen über die umgebende Struktur, wie z. B. den umschließenden Textblock, Rahmen, die Tabelle oder die Liste, melden. Die Formate der umschließenden Strukturen können auch direkt über den Cursor abgerufen werden.
Verwendung eines Cursors
Die Hauptanwendung eines Cursors ist das Einfügen oder Ändern von Text innerhalb eines Blocks. Hierfür kann der Cursor eines Texteditors verwendet werden:
QTextEdit *editor = new QTextEdit(); QTextCursor cursor(editor->textCursor());
Alternativ können wir einen Cursor auch direkt aus einem Dokument beziehen:
QTextDocument *document = new QTextDocument(editor); QTextCursor cursor(document);
Der Cursor wird am Anfang des Dokuments positioniert, so dass wir in den ersten (leeren) Block des Dokuments schreiben können.
Cursor-Operationen gruppieren
Eine Reihe von Bearbeitungsvorgängen kann in einem Paket zusammengefasst werden, so dass sie in einer einzigen Aktion wiedergegeben oder rückgängig gemacht werden können. Dies wird durch die Verwendung der Funktionen beginEditBlock()
und endEditBlock()
erreicht, wie im folgenden Beispiel, in dem wir das Wort auswählen, das den Cursor enthält:
cursor.beginEditBlock(); cursor.movePosition(QTextCursor::StartOfWord); cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); cursor.endEditBlock();
Wenn Bearbeitungsvorgänge nicht gruppiert werden, zeichnet das Dokument die einzelnen Vorgänge automatisch auf, so dass sie später rückgängig gemacht werden können. Die Gruppierung von Operationen in größeren Paketen kann die Bearbeitung sowohl für den Benutzer als auch für die Anwendung effizienter machen, aber es muss darauf geachtet werden, dass nicht zu viele Operationen gruppiert werden, da der Benutzer möglicherweise eine fein abgestufte Kontrolle über den Rückgängigmachungsprozess wünscht.
Mehrere Cursor
Mehrere Cursor können zur gleichzeitigen Bearbeitung desselben Dokuments verwendet werden, obwohl nur ein Cursor in einem QTextEdit Widget für den Benutzer sichtbar ist. Die QTextDocument stellt sicher, dass jeder Cursor den Text korrekt schreibt und die anderen nicht beeinträchtigt.
Dokumentenelemente einfügen
QTextCursor bietet mehrere Funktionen, mit denen die Struktur eines Rich-Text-Dokuments verändert werden kann. Im Allgemeinen ermöglichen diese Funktionen die Erstellung von Dokumentelementen mit relevanten Formatierungsinformationen, die an der Position des Cursors in das Dokument eingefügt werden.
Die erste Gruppe von Funktionen fügt Elemente auf Blockebene ein und aktualisiert die Cursorposition, gibt aber nicht das eingefügte Element zurück:
- insertBlock() fügt einen neuen Textblock (Absatz) an der Position des Cursors in das Dokument ein und setzt den Cursor an den Anfang des neuen Blocks.
- insertFragment() fügt ein bestehendes Textfragment an der Position des Cursors in ein Dokument ein.
- insertImage() fügt ein Bild an der Position des Cursors in ein Dokument ein.
- insertText() fügt einen Text an der Position des Cursors in das Dokument ein.
Sie können den Inhalt des eingefügten Elements über die Cursorschnittstelle überprüfen.
Die zweite Gruppe von Funktionen fügt Elemente ein, die dem Dokument eine Struktur geben, und gibt die eingefügte Struktur zurück:
- insertFrame() fügt einen Rahmen in das Dokument nach dem aktuellen Block des Cursors ein und setzt den Cursor an den Anfang des leeren Blocks im neuen Rahmen.
- insertList() fügt eine Liste an der Position des Cursors in das Dokument ein und setzt den Cursor an den Anfang des ersten Elements der Liste.
- insertTable() fügt eine Tabelle in das Dokument nach dem aktuellen Block des Cursors ein und setzt den Cursor an den Anfang des Blocks nach der Tabelle.
Diese Elemente enthalten entweder andere Elemente im Dokument oder fassen sie zusammen.
Text und Textfragmente
Text kann in den aktuellen Block im aktuellen Zeichenformat oder in einem benutzerdefinierten Format eingefügt werden, das zusammen mit dem Text angegeben wird:
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);
Sobald das Zeichenformat mit einem Cursor verwendet wurde, wird dieses Format zum Standardformat für jeden mit diesem Cursor eingefügten Text, bis ein anderes Zeichenformat angegeben wird.
Wird ein Cursor zum Einfügen von Text ohne Angabe eines Zeichenformats verwendet, erhält der Text das an dieser Position im Dokument verwendete Zeichenformat.
Blöcke
Textblöcke werden mit der Funktion insertBlock() in das Dokument eingefügt.
QTextBlockFormat backgroundFormat = blockFormat; backgroundFormat.setBackground(QColor("lightGray")); cursor.setBlockFormat(backgroundFormat);
Der Cursor wird an den Anfang des neuen Blocks gesetzt.
Rahmen
Rahmen werden mit Hilfe des Cursors in ein Dokument eingefügt. Sie werden innerhalb des aktuellen Rahmens des Cursors nach dem aktuellen Block platziert. Der folgende Code zeigt, wie ein Rahmen zwischen zwei Textblöcken im Stammrahmen eines Dokuments eingefügt werden kann. Zunächst suchen wir den aktuellen Rahmen des Cursors:
QTextFrame *mainFrame = cursor.currentFrame(); cursor.insertText(...);
Wir fügen Text in diesen Rahmen ein und richten dann ein Rahmenformat für den untergeordneten Rahmen ein:
QTextFrameFormat frameFormat; frameFormat.setMargin(32); frameFormat.setPadding(8); frameFormat.setBorder(4);
Das Rahmenformat gibt dem Rahmen einen äußeren Rand von 32 Pixeln, eine innere Auffüllung von 8 Pixeln und einen 4 Pixel breiten Rahmen. Weitere Informationen zu Rahmenformaten finden Sie in der Dokumentation QTextFrameFormat.
Der Rahmen wird nach dem vorangehenden Text in das Dokument eingefügt:
cursor.insertFrame(frameFormat); cursor.insertText(...);
Unmittelbar nach dem Einfügen des Rahmens fügen wir Text in das Dokument ein. Da sich der Textcursor innerhalb des Rahmens befindet, wenn er in das Dokument eingefügt wird, wird dieser Text auch innerhalb des Rahmens eingefügt.
Schließlich positionieren wir den Cursor außerhalb des Rahmens, indem wir die letzte verfügbare Cursorposition innerhalb des Rahmens nehmen, die wir zuvor aufgezeichnet haben:
cursor = mainFrame->lastCursorPosition(); cursor.insertText(...);
Der zuletzt eingefügte Text wird nach dem untergeordneten Rahmen in das Dokument eingefügt. Da jeder Rahmen mit Textblöcken aufgefüllt wird, ist sichergestellt, dass immer weitere Elemente mit einem Cursor eingefügt werden können.
Tabellen
Tabellen werden mit Hilfe des Cursors in das Dokument eingefügt und innerhalb des aktuellen Rahmens des Cursors nach dem aktuellen Block platziert:
QTextCursor cursor(editor->textCursor()); QTextTable *table = cursor.insertTable(rows, columns, tableFormat);
Tabellen können mit einem bestimmten Format erstellt werden, das die allgemeinen Eigenschaften der Tabelle festlegt, z. B. die Ausrichtung, die Hintergrundfarbe und die verwendeten Zellenabstände. Außerdem können die Einschränkungen für jede Spalte festgelegt werden, so dass jede Spalte eine feste Breite hat oder die Größe entsprechend dem verfügbaren Platz angepasst werden kann.
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);
Die Spalten in der oben erstellten Tabelle nehmen jeweils einen bestimmten Prozentsatz der verfügbaren Breite ein. Beachten Sie, dass das Tabellenformat optional ist; wenn Sie eine Tabelle ohne Format einfügen, werden einige sinnvolle Standardwerte für die Eigenschaften der Tabelle verwendet.
Da die Zellen auch andere Dokumentelemente enthalten können, können auch sie nach Bedarf formatiert und gestaltet werden.
Text kann der Tabelle hinzugefügt werden, indem Sie mit dem Cursor zu jeder Zelle navigieren und Text einfügen.
cell = table->cellAt(0, 0); cellCursor = cell.firstCursorPosition(); cellCursor.insertText(tr("Week"), charFormat);
Auf diese Weise können wir einen einfachen Zeitplan erstellen:
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); } } }
Listen
Listen mit Blockelementen können automatisch erstellt und an der aktuellen Cursorposition in das Dokument eingefügt werden. Für jede Liste, die auf diese Weise erstellt wird, muss ein Listenformat angegeben werden:
QTextListFormat listFormat; if (list) { listFormat = list->format(); listFormat.setIndent(listFormat.indent() + 1); } listFormat.setStyle(QTextListFormat::ListDisc); cursor.insertList(listFormat);
Der obige Code prüft zunächst, ob sich der Cursor innerhalb einer bestehenden Liste befindet, und wenn ja, gibt er dem Listenformat für die neue Liste eine geeignete Einrückungsebene. So können verschachtelte Listen mit zunehmender Einrückung erstellt werden. Eine anspruchsvollere Implementierung würde auch verschiedene Arten von Symbolen für die Aufzählungspunkte in jeder Ebene der Liste verwenden.
Bilder
Inline-Bilder werden den Dokumenten auf die übliche Weise über den Cursor hinzugefügt. Im Gegensatz zu vielen anderen Elementen werden alle Bildeigenschaften durch das Format des Bildes festgelegt. Dies bedeutet, dass ein QTextImageFormat Objekt erstellt werden muss, bevor ein Bild eingefügt werden kann:
QTextImageFormat imageFormat; imageFormat.setName(":/images/advert.png"); cursor.insertImage(imageFormat);
Der Bildname verweist auf einen Eintrag in der Ressourcendatei der Anwendung. Die Methode, mit der dieser Name abgeleitet wird, ist in The Qt Resource System beschrieben.
Beispiele
Rich Text wird in Textdokumenten gespeichert, die entweder durch den Import von HTML aus einer externen Quelle oder mit Hilfe von QTextCursor erstellt werden können.
Manipulation von Rich Text
Der einfachste Weg, ein Rich-Text-Dokument zu verwenden, ist die Klasse QTextEdit, die eine editierbare Ansicht eines Dokuments bietet. Der folgende Code importiert HTML in ein Dokument und zeigt das Dokument mit einem Textbearbeitungs-Widget an.
QTextEdit *editor = new QTextEdit(parent); editor->setHtml(aStringContainingHTMLtext); editor->show();
Sie können das Dokument mit der Funktion document() aus der Textbearbeitung abrufen. Das Dokument kann dann programmatisch mit der Klasse QTextCursor bearbeitet werden. Diese Klasse ist einem Bildschirmcursor nachempfunden, und die Bearbeitungsvorgänge folgen der gleichen Semantik. Der folgende Code ändert die erste Zeile des Dokuments in eine fette Schriftart, wobei alle anderen Schrifteigenschaften unberührt bleiben. Der Editor wird automatisch aktualisiert, um die Änderungen an den zugrunde liegenden Dokumentdaten widerzuspiegeln.
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);
Beachten Sie, dass der Cursor vom Anfang der ersten Zeile zum Ende verschoben wurde, aber einen Anker am Anfang der Zeile beibehalten hat. Dies demonstriert die cursorbasierten Auswahlmöglichkeiten der Klasse QTextCursor.
Erzeugen eines Kalenders
Mit dem cursorbasierten Ansatz kann sehr schnell Rich Text erzeugt werden. Das folgende Beispiel zeigt einen einfachen Kalender in einem QTextEdit Widget mit fetten Überschriften für die Wochentage:
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); } }
Das obige Beispiel zeigt, wie einfach es ist, mit einem Minimum an Code schnell neue Rich-Text-Dokumente zu erzeugen. Obwohl wir einen einfachen Kalender mit festem Raster generiert haben, um nicht zu viel Code zu zitieren, bietet Scribe viel anspruchsvollere Layout- und Formatierungsfunktionen.
© 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.