Struktur von Rich-Text-Dokumenten

Textdokumente werden durch die Klasse QTextDocument dargestellt, die Informationen über die interne Darstellung des Dokuments und seine Struktur enthält und Änderungen verfolgt, um Rückgängig-/Wiederherstellungsfunktionen bereitzustellen.

Die strukturierte Darstellung eines Textdokuments stellt seinen Inhalt als eine Hierarchie von Textblöcken, Rahmen, Tabellen und anderen Objekten dar. Diese geben dem Dokument eine logische Struktur und beschreiben, wie ihr Inhalt angezeigt wird. Im Allgemeinen werden Rahmen und Tabellen zur Gruppierung anderer Strukturen verwendet, während Textblöcke die eigentlichen Textinformationen enthalten.

Neue Elemente werden programmatisch mit einem QTextCursor oder mit Hilfe eines Editor-Widgets wie QTextEdit erstellt und in das Dokument eingefügt. Elemente können bei ihrer Erstellung mit einem bestimmten Format versehen werden; andernfalls nehmen sie das aktuelle Format des Cursors für das Element an.

Grundlegende Struktur

Die "oberste Ebene" eines Dokuments kann wie folgt aufgebaut sein. Jedes Dokument enthält immer einen Wurzelrahmen, und dieser enthält immer mindestens einen Textblock.

Bei Dokumenten mit Textinhalt enthält der Wurzelrahmen normalerweise eine Reihe von Blöcken und anderen Elementen.

Sequenzen von Rahmen und Tabellen werden in einem Dokument immer durch Textblöcke getrennt, auch wenn die Textblöcke keine Informationen enthalten. Auf diese Weise wird sichergestellt, dass neue Elemente immer zwischen bestehenden Strukturen eingefügt werden können.

In diesem Kapitel werden die einzelnen Strukturelemente eines Rich-Text-Dokuments betrachtet, ihre Eigenschaften und Verwendungszwecke erläutert und gezeigt, wie man ihren Inhalt untersuchen kann. Die Bearbeitung von Dokumenten wird in Die QTextCursor-Schnittstelle beschrieben.

Rich Text Dokumente

QTextDocument Objekte enthalten alle Informationen, die für die Erstellung von Rich-Text-Dokumenten erforderlich sind. Auf Textdokumente kann auf zwei komplementäre Arten zugegriffen werden: als linearer Puffer für Redakteure und als Objekthierarchie, die für Layout-Engines nützlich ist. Im hierarchischen Dokumentenmodell entsprechen die Objekte im Allgemeinen visuellen Elementen wie Rahmen, Tabellen und Listen. Auf einer niedrigeren Ebene beschreiben diese Elemente Eigenschaften wie den Textstil und die Ausrichtung. Die lineare Darstellung des Dokuments wird für die Bearbeitung und Manipulation des Dokumentinhalts verwendet.

Obwohl QTextEdit die Anzeige und Bearbeitung von Rich Text erleichtert, können Dokumente auch unabhängig von einem Editor-Widget verwendet werden:

QTextDocument *newDocument = new QTextDocument;

Sie können aber auch aus einem bestehenden Editor extrahiert werden:

QTextEdit *editor = new QTextEdit;
QTextDocument *editorDocument = editor->document();

Diese Flexibilität ermöglicht es Anwendungen, mehrere Rich-Text-Dokumente zu bearbeiten, ohne den Overhead mehrerer Editor-Widgets oder die Notwendigkeit, Dokumente in einem Zwischenformat zu speichern.

Ein leeres Dokument enthält einen Root-Frame, der wiederum einen einzelnen leeren Textblock enthält. Frames sorgen für eine logische Trennung zwischen den Teilen des Dokuments, haben aber auch Eigenschaften, die bestimmen, wie sie beim Rendern aussehen. Eine Tabelle ist ein spezieller Rahmentyp, der aus einer Reihe von Zellen besteht, die in Zeilen und Spalten angeordnet sind, von denen jede weitere Strukturen und Text enthalten kann. Tabellen bieten Verwaltungs- und Layout-Funktionen, mit denen flexible Konfigurationen von Zellen erstellt werden können.

Textblöcke enthalten Textfragmente, von denen jedes Text- und Zeichenformatinformationen enthält. Texteigenschaften werden sowohl auf der Zeichenebene als auch auf der Blockebene definiert. Auf der Zeichenebene können Eigenschaften wie Schriftfamilie, Textfarbe und Schriftstärke festgelegt werden. Die Eigenschaften auf Blockebene steuern das Erscheinungsbild und das Verhalten des Textes auf höherer Ebene, z. B. die Richtung des Textflusses, die Ausrichtung und die Hintergrundfarbe.

Die Dokumentstruktur wird nicht direkt manipuliert. Die Bearbeitung erfolgt über eine cursorbasierte Schnittstelle. Die Textcursorschnittstelle fügt automatisch neue Dokumentelemente in den Wurzelrahmen ein und sorgt dafür, dass dieser bei Bedarf mit leeren Blöcken aufgefüllt wird.

Wir erhalten den Wurzelrahmen auf folgende Weise:

    QTextDocument *editorDocument = editor->document();
    QTextFrame *root = editorDocument->rootFrame();

Bei der Navigation in der Dokumentstruktur ist es sinnvoll, mit dem Wurzelrahmen zu beginnen, da er den Zugriff auf die gesamte Dokumentstruktur ermöglicht.

Dokumentenelemente

Rich-Text-Dokumente bestehen in der Regel aus allgemeinen Elementen wie Absätzen, Rahmen, Tabellen und Listen. Diese werden in einem QTextDocument durch die Klassen QTextBlock, QTextFrame, QTextTable und QTextList dargestellt. Anders als die anderen Elemente in einem Dokument werden Bilder durch speziell formatierte Textfragmente dargestellt. Dadurch können sie formatiert inline mit dem umgebenden Text platziert werden.

Die grundlegenden strukturellen Bausteine in Dokumenten sind QTextBlock und QTextFrame. Die Blöcke selbst enthalten Fragmente von Rich-Text (QTextFragment), aber diese haben keinen direkten Einfluss auf die übergeordnete Struktur eines Dokuments.

Elemente, die andere Dokumentelemente zusammenfassen können, sind typischerweise Unterklassen von QTextObject und lassen sich in zwei Kategorien einteilen: Elemente, die Textblöcke zusammenfassen, sind Unterklassen von QTextBlockGroup, und solche, die Rahmen und andere Elemente zusammenfassen, sind Unterklassen von QTextFrame.

Textblöcke

Textblöcke werden von der Klasse QTextBlock bereitgestellt.

Textblöcke fassen Textfragmente mit unterschiedlichen Zeichenformaten zusammen und werden verwendet, um Absätze im Dokument darzustellen. Jeder Block enthält in der Regel eine Reihe von Textfragmenten mit unterschiedlichen Stilen. Fragmente werden erstellt, wenn Text in das Dokument eingefügt wird, und weitere Fragmente werden hinzugefügt, wenn das Dokument bearbeitet wird. Das Dokument teilt, verschmilzt und entfernt Fragmente, um die verschiedenen Textstile im Block effizient darzustellen.

Die Fragmente innerhalb eines bestimmten Blocks können mit Hilfe einer QTextBlock::iterator untersucht werden, um die interne Struktur des Blocks zu durchlaufen:

    QTextBlock::iterator it;
    for (it = currentBlock.begin(); !(it.atEnd()); ++it) {
        QTextFragment currentFragment = it.fragment();
        if (currentFragment.isValid())
            processFragment(currentFragment);
    }

Blöcke werden auch zur Darstellung von Listenelementen verwendet. Daher können Blöcke ihre eigenen Zeichenformate definieren, die Informationen über die Dekoration auf Blockebene enthalten, wie z. B. die Art der Aufzählungspunkte, die für Listenelemente verwendet werden. Die Formatierung für den Block selbst wird durch die Klasse QTextBlockFormat beschrieben und beschreibt Eigenschaften wie Textausrichtung, Einrückung und Hintergrundfarbe.

Obwohl ein bestimmtes Dokument komplexe Strukturen enthalten kann, können wir, sobald wir einen Verweis auf einen gültigen Block im Dokument haben, zwischen den einzelnen Textblöcken in der Reihenfolge navigieren, in der sie geschrieben wurden:

    QTextBlock currentBlock = textDocument->begin();

    while (currentBlock.isValid()) {
        processBlock(currentBlock);
        currentBlock = currentBlock.next();
    }

Diese Methode ist nützlich, wenn Sie nur den Rich Text aus einem Dokument extrahieren möchten, da Rahmen, Tabellen und andere Arten von Strukturen ignoriert werden.

QTextBlock bietet Vergleichsoperatoren, die die Bearbeitung von Blöcken erleichtern: operator==() und operator!=() werden verwendet, um zu prüfen, ob zwei Blöcke gleich sind, und operator<() wird verwendet, um festzustellen, welcher Block zuerst in einem Dokument vorkommt.

Frames

Frames werden von der Klasse QTextFrame bereitgestellt.

Textrahmen fassen Textblöcke und untergeordnete Rahmen zusammen und schaffen so Dokumentstrukturen, die größer als Absätze sind. Das Format eines Rahmens legt fest, wie er gerendert und auf der Seite positioniert wird. Rahmen werden entweder in den Textfluss eingefügt oder sie schweben am linken oder rechten Rand der Seite. Jedes Dokument enthält einen Hauptrahmen, der alle anderen Dokumentelemente enthält. Folglich haben alle Rahmen mit Ausnahme des Wurzelrahmens einen übergeordneten Rahmen.

Da Textblöcke verwendet werden, um andere Dokumentelemente zu trennen, enthält jeder Rahmen immer mindestens einen Textblock und null oder mehr untergeordnete Rahmen. Wir können den Inhalt eines Rahmens untersuchen, indem wir einen QTextFrame::iterator verwenden, um die untergeordneten Elemente des Rahmens zu durchlaufen:

    QTextFrame::iterator it;
    for (it = frame->begin(); !(it.atEnd()); ++it) {

        QTextFrame *childFrame = it.currentFrame();
        QTextBlock childBlock = it.currentBlock();

        if (childFrame)
            processFrame(childFrame);
        else if (childBlock.isValid())
            processBlock(childBlock);
    }

Beachten Sie, dass der Iterator sowohl Rahmen als auch Blöcke auswählt, so dass es notwendig ist, zu prüfen, auf welche Elemente er sich bezieht. Auf diese Weise können wir in der Dokumentstruktur Frame für Frame navigieren und bei Bedarf dennoch auf Textblöcke zugreifen. Die Klassen QTextBlock::iterator und QTextFrame::iterator können auf komplementäre Weise verwendet werden, um die gewünschte Struktur aus einem Dokument zu extrahieren.

Tabellen

Tabellen werden von der Klasse QTextTable bereitgestellt.

Tabellen sind Sammlungen von Zellen, die in Zeilen und Spalten angeordnet sind. Jede Tabellenzelle ist ein Dokumentenelement mit einem eigenen Zeichenformat, kann aber auch andere Elemente wie Rahmen und Textblöcke enthalten. Tabellenzellen werden automatisch erstellt, wenn die Tabelle aufgebaut wird oder wenn zusätzliche Zeilen oder Spalten hinzugefügt werden. Sie können auch zwischen Tabellen verschoben werden.

QTextTable ist eine Unterklasse von QTextFrame, so dass Tabellen in der Dokumentstruktur wie Rahmen behandelt werden. Für jeden Rahmen, auf den wir im Dokument stoßen, können wir prüfen, ob er eine Tabelle darstellt, und ihn auf eine andere Weise behandeln:

    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(childTable);
            else
                processFrame(childFrame);

        } else if (childBlock.isValid()) {
            processBlock(childBlock);
        }
    }

Die Zellen innerhalb einer bestehenden Tabelle können durch Iteration durch die Zeilen und Spalten untersucht werden.

    for (int row = 0; row < table->rows(); ++row) {
        for (int column = 0; column < table->columns(); ++column) {
            QTextTableCell tableCell = table->cellAt(row, column);
            processTableCell(tableCell);
        }
    }

Listen

Listen werden von der Klasse QTextList bereitgestellt.

Listen sind Aneinanderreihungen von Textblöcken, die auf die übliche Weise formatiert sind, aber auch die üblichen Listendekorationen wie Aufzählungspunkte und Aufzählungszeichen enthalten. Listen können verschachtelt werden und werden eingerückt, wenn das Format der Liste eine Einrückung ungleich Null vorsieht.

Wir können auf jedes Listenelement durch seinen Index in der Liste verweisen:

    for (int index = 0; index < list->count(); ++index) {
        QTextBlock listItem = list->item(index);
        processListItem(listItem);
    }

Da QTextList eine Unterklasse von QTextBlockGroup ist, gruppiert es die Listenelemente nicht als untergeordnete Elemente, sondern bietet stattdessen verschiedene Funktionen für deren Verwaltung. Das bedeutet, dass jeder Textblock, den wir beim Durchlaufen eines Dokuments finden, eigentlich ein Listenelement sein kann. Mit dem folgenden Code können wir sicherstellen, dass die Listenelemente korrekt identifiziert werden:

    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);
            }
        }
    }

Bilder

Bilder in QTextDocument werden durch Textfragmente dargestellt, die über den Ressourcenmechanismus auf externe Bilder verweisen. Bilder werden über die Cursor-Schnittstelle erstellt und können später durch Änderung des Zeichenformats des Textfragments des Bildes geändert werden:

    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);
        }
    }

Das Fragment, das das Bild repräsentiert, kann durch Iteration über die Fragmente in dem Textblock, der das Bild enthält, gefunden werden.

© 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.