リッチテキスト文書の構造

テキストドキュメントはQTextDocument クラスで表現されます。このクラスはドキュメントの内部表現とその構造に関する情報を持ち、アンドゥ/リドゥ機能を提供するために変更を追跡します。

テキスト文書の構造表現は、その内容をテキストブロック、フレーム、テーブル、その他のオブジェクトの階層として表示します。これらは文書に論理的な構造を与え、その内容がどのように表示されるかを記述します。一般的に、フレームとテーブルは他の構造をグループ化するために使用され、テキストブロックには実際のテキスト情報が含まれます。

新しい要素は、QTextCursor を使ってプログラムで作成したり、QTextEdit などのエディタ・ウィジェットを使ってドキュメントに挿入したりします。そうでない場合は、カーソルの現在の書式が適用されます。

基本構造

ドキュメントの "トップレベル "は、図示のような形で配置されます。各文書には必ずルートフレームがあり、これには必ず少なくとも1つのテキストブロックが含まれます。

いくつかのテキストコンテンツを持つ文書では、ルートフレームは通常、一連のブロックや他の要素を含んでいます。

フレームや表のシーケンスは、たとえテキストブロックに情報がなくても、文書内では常にテキストブロックで区切られます。これによって、既存の構造の間に常に新しい要素を挿入できるようになります。

この章では、リッチテキスト文書で使用される各構造要素を見て、その特徴と用途を概説し、その内容を調べる方法を示します。文書の編集については、「QTextCursor インターフェース」で説明します。

リッチテキスト・ドキュメント

QTextDocument オブジェクトには、リッチテキスト文書を作成するために必要なすべての情報が含まれています。テキスト・ドキュメントは、エディターが使用する線形バッファと、レイアウト・エンジンに有用なオブジェクト階層という、2つの相補的な方法でアクセスすることができます。階層型文書モデルでは、オブジェクトは一般にフレームや表、リストなどの視覚的要素に対応します。より低いレベルでは、これらの要素はテキストのスタイルや配置などのプロパティを記述します。文書の線形表現は、文書の内容の編集や操作に使われます。

QTextEdit 、リッチテキストの表示や編集が簡単にできますが、ドキュメントはエディタ・ウィジェットなどとは独立して使用することもできます:

QTextDocument *newDocument = new QTextDocument;

あるいは、既存のエディタから抽出することもできます:

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

この柔軟性により、アプリケーションは複数のエディタ・ウィジェットのオーバーヘッドなしに複数のリッチテキスト・ドキュメントを扱ったり、ドキュメントを何らかの中間フォーマットで保存する必要がなくなります。

空のドキュメントはルートフレームを含み、それ自体が1つの空のテキストブロックを含みます。フレームはドキュメントの各部分を論理的に分離しますが、レンダリング時にどのように表示されるかを決めるプロパティも持っています。テーブルは特殊なタイプのフレームで、行と列に配置された多数のセルから構成され、各セルにはさらに構造やテキストを含めることができます。テーブルには、セルの柔軟な構成を作成できる管理機能とレイアウト機能があります。

テキスト・ブロックにはテキスト・フラグメントが含まれ、各フラグメントはテキストと文字書式情報を指定する。テキスト・プロパティは、文字レベルとブロック・レベルの両方で定義されます。文字レベルでは、フォントファミリ、テキストの色、フォントの太さなどのプロパティを指定できます。ブロック・レベルのプロパティは、テキストの流れ方向、配置、背景色など、テキストの上位レベルの外観や動作を制御します。

文書構造は直接操作されません。編集はカーソルベースのインターフェースを通じて行われます。テキスト・カーソル・インターフェースは、新しい文書要素を自動的にルート・フレームに挿入し、必要に応じて空のブロックで埋めるようにします。

ルートフレームは次のようにして取得する:

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

文書構造をナビゲートする場合、ルートフレームから始めると文書構造全体にアクセスできるので便利です。

文書要素

リッチテキスト文書は通常、段落、フレーム、表、リストといった一般的な要素で構成されています。これらはQTextBlockQTextFrameQTextTableQTextList クラスによってQTextDocument で表現されます。文書の他の要素とは異なり、画像は特別にフォーマットされたテキスト断片で表現されます。これによって画像は、周囲のテキストとインラインでフォーマットされて配置されます。

文書の基本的な構造構成ブロックはQTextBlockQTextFrame です。ブ ロ ッ ク それ自体に リ ッ チテ キ ス ト の断片が含まれてい ますが (QTextFragment )、 こ れ ら は文書の上位構造に直接影響を与え る わけではあ り ません。

他の文書要素を グループ化で き る 要素は通常、QTextObject のサブ ク ラ ス であ り 、 2 つの カ テ ゴ リ に分類 さ れます:テ キ ス ト ブ ロ ッ ク を ま と め る 要素はQTextBlockGroup のサブ ク ラ ス であ り 、 フ レームやその他の要素を ま と め る 要素はQTextFrame のサブ ク ラ ス です。

テキスト・ブロック

テ キ ス ト ブ ロ ッ ク はQTextBlock ク ラ ス に よ っ て提供 さ れます。

テ キ ス ト ブ ロ ッ ク は、 さ ま ざ ま な文字書式を持つテ キ ス ト の断片を ま と めた も のであ り 、 文書内の段落を表現す る ために用い ら れます。各ブ ロ ッ ク は通常、 さ ま ざ ま な ス タ イ ルを持つ複数のテ キ ス ト 断片を内容 と し て持ち ます。断片はテ キ ス ト を文書に挿入す る 際に作成 さ れ、 文書を編集す る 際に も さ ら に追加 さ れます。文書は、 ブロック内のテキストの異なるスタイルを効率的に表現するために、フラグメントを分割・結合・削除します。

あ る ブ ロ ッ ク 内の断片は、QTextBlock::iterator を使っ てブ ロ ッ ク の内部構造をた ど る こ と で調べる こ と がで き ます:

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

ブロックはリスト項目の表現にも使われます。ブ ロ ッ ク は リ ス ト 項目を表現す る ために も 用い ら れ る ので、 ブ ロ ッ ク はそれ自身の文字書式を定義す る こ と がで き 、 こ れはブ ロ ッ ク レ ベルの装飾に関す る 情報を持っ てい ます。ブロック自体の書式はQTextBlockFormat クラスで記述され、テキストの配置やインデント、背景色などのプロパティを記述します。

与えられた文書には複雑な構造が含まれているかもしれませんが、いったん文書内の有効なブロックへの参照があれば、各テキストブロック間を書かれた順番に移動することができます:

    QTextBlock currentBlock = textDocument->begin();

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

この方法は、フレームや表などの構造を無視するので、文書からリッチテキストだけを抽出したい場合に便利です。

QTextBlock operator==() と () は、 2 つのブ ロ ッ ク が同 じ か ど う か を調べる ために用い ら れ、 () は、 ど ち ら が文書内で最初に出現す る か を決定す る ために用い ら れます。operator!= operator<

フレーム

フレームはQTextFrame クラスで提供されています。

テキストフレームは、テキストブロックと子フレームをまとめ、段落よりも大きな文書構造を作ります。フレームの書式は、それがどのように表示され、ページ上に配置されるかを指定します。フレームはテキストフローに挿入されるか、ページの左側か右側にフロートします。各文書にはルートフレームがあり、そこに他の文書要素がすべて含まれます。その結果、ルートフレーム以外のすべてのフレームは親フレームを持ちます。

テキスト・ブロックは他の文書要素を区切るために使われるので、各フレームには必ず少なくとも1つのテキスト・ブロックと、0個以上の子フレームが含まれます。QTextFrame::iterator を使ってフレームの子要素を走査することで、フレームの内容を調べることができます:

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

イテレータはフレームとブロックの両方を選択するので、どちらを参照しているかをチェックする必要があることに注意してください。イテレータはフレームとブロックの両方を選択するので、どちらを参照しているかをチェックする必要があることに注意してください。これにより、フレーム単位でドキュメント構造をナビゲートしながらも、必要に応じてテキストブロックにアクセスすることができます。QTextBlock::iteratorQTextFrame::iterator の両クラスは、ドキュメントから必要な構造を抽出するために補完的に使用することができます。

テーブルはQTextTable クラスによって提供されます。

表は、行と列に配置されたセルの集まりです。各表セルは、それ自身の文字書式を持つ文書要素ですが、フレームやテキストブロックなどの他の要素を含むこともできます。表セルは、表を作成するときや、行や列を追加するときに自動的に作成されます。また、テーブル間で移動することもできます。

QTextTable は のサブクラスなので、テーブルはドキュメント構造におけるフレームのように扱われます。文書内で出会う各フレームについて、それが表を表しているかどうかをテストし、異なる方法でそれを扱うことができます:QTextFrame

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

既存の表内のセルは、行と列を繰り返しながら調べることができます。

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

リスト

リストはQTextList

リストはテキスト・ブロックの並びで、通常の書式で記述されますが、箇条書きや列挙などの標準的なリスト装飾も提供します。リストは入れ子にすることができ、リストの書式でゼロ以外のインデントが指定されている場合はインデントされます。

リストの各項目は、リスト内のインデックスで参照できます:

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

QTextListQTextBlockGroup のサブクラスなので、リスト項目を子要素としてグループ化することはなく、代わりにそれらを管理するためのさまざまな関数を提供します。こ れは、 文書をた ど る 際に見つか る ど のテ キ ス ト ブ ロ ッ ク も 、 実は リ ス ト 項目であ る 可能性があ る こ と を意味 し ます。以下のコードを使うことで、リスト項目が正しく識別されるようにすることができます:

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

画像

QTextDocument 、画像はリソース・メカニズムを通じて外部画像を参照するテキスト・フラグメントで表現されます。画像はカーソルインターフェイスを使って作成され、画像のテキストフラグメントの文字書式を変更することで、後から変更することができます:

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

画像を表すフラグメントは、画像を含むテキストブロック内のフラグメントを反復処理することで見つけることができます。

このドキュメントに含まれるコントリビューションの著作権は、それぞれの所有者に帰属します 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。