このページの内容

QTextCursor インターフェース

ドキュメントは、QTextCursor クラスが提供するインターフェースを介して編集できます。カーソルは、コンストラクタを使用して作成するか、エディタウィジェットから取得します。このカーソルは、ユーザーがエディタ上で自ら行う操作と完全に一致する編集操作を実行するために使用されます。 その結果、ドキュメントの構造に関する情報もカーソルを介して利用可能となり、これにより構造の変更が可能になります。編集にカーソル指向のインターフェースを使用することで、編集操作を容易に視覚化できるため、開発者にとってカスタムエディタの作成プロセスが簡素化されます。

QTextCursor クラスは、ドキュメント内で選択したテキストに関する情報も保持しており、これもまた、エディタ内でユーザーがテキストを選択する操作と概念的に類似したモデルに従っています。

リッチテキスト文書には複数のカーソルが関連付けられることがあり、それぞれのカーソルには、文書内での位置や、そのカーソルが保持している選択範囲に関する情報が含まれています。このカーソルベースのパラダイムにより、テキストの切り取りや貼り付けといった一般的な操作をプログラムで簡単に実装できるだけでなく、文書に対してより複雑な編集操作を行うことも可能になります。

この章では、テキストや文書要素の基本的な挿入から、文書構造のより複雑な操作に至るまで、カーソルを使用して実行する必要のある一般的な編集操作のほとんどについて説明します。

カーソルベースの編集

最も単純なレベルでは、テキスト文書は一連の文字列で構成されており、文書内のテキストのブロック構造を表すために何らかの方法でマークアップされています。QTextCursor は、QTextDocument の内容を文字レベルで操作できるカーソルベースのインターフェースを提供します。 要素(ブロック、フレーム、表など)も文字ストリーム内にエンコードされているため、カーソルによって文書構造そのものを変更することができます。

カーソルは親ドキュメント内での位置を追跡し、囲んでいるテキストブロック、フレーム、表、リストなど、周囲の構造に関する情報を報告することができます。また、囲んでいる構造のフォーマットも、カーソルを介して直接取得することができます。

カーソルの使用

カーソルの主な用途は、ブロック内のテキストを挿入または変更することです。これを行うには、テキストエディタのカーソルを使用できます:

    QTextEdit *editor = new QTextEdit();
    QTextCursor cursor(editor->textCursor());

あるいは、ドキュメントから直接カーソルを取得することもできます:

    QTextDocument *document = new QTextDocument(editor);
    QTextCursor cursor(document);

カーソルはドキュメントの先頭に配置されるため、ドキュメント内の最初の(空の)ブロックに書き込むことができます。

カーソル操作のグループ化

一連の編集操作をまとめてパッケージ化することで、それらをまとめて再生したり、1つの操作でまとめて元に戻したりすることができます。これは、beginEditBlock() およびendEditBlock() 関数を次のように使用することで実現されます。以下の例では、カーソルが含まれている単語を選択しています:

    cursor.beginEditBlock();
    cursor.movePosition(QTextCursor::StartOfWord);
    cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
    cursor.endEditBlock();

編集操作がグループ化されていない場合、ドキュメントは後で元に戻せるように個々の操作を自動的に記録します。操作を大きなパッケージにグループ化することで、ユーザーとアプリケーションの両方にとって編集効率を高めることができますが、ユーザーが元に戻すプロセスを細かく制御したい場合もあるため、あまり多くの操作をまとめてグループ化しないよう注意が必要です。

複数のカーソル

複数のカーソルを使用して同じ文書を同時に編集できますが、QTextEdit ウィジェット上でユーザーに表示されるのは1つだけです。QTextDocument は、各カーソルがテキストを正しく書き込み、他のカーソルと干渉しないようにします。

ドキュメント要素の挿入

QTextCursor には、リッチテキスト文書の構造を変更するために使用できるいくつかの関数が用意されています。一般的に、これらの関数を使用すると、関連する書式設定情報を伴う文書要素を作成でき、それらはカーソルの位置に文書内に挿入されます。

最初の関数群は、ブロックレベル要素を挿入し、カーソル位置を更新しますが、挿入された要素を返しません。

  • insertBlock() は、カーソルの位置に新しいテキストブロック(段落)を文書に挿入し、カーソルを新しいブロックの先頭に移動させます。
  • insertFragment() は、既存のテキスト断片をドキュメント内のカーソル位置に挿入し、カーソルを新しいブロックの先頭に移動させます。
  • insertImage() は、カーソル位置に画像を文書に挿入します。
  • insertText() は、ドキュメントのカーソル位置にテキストを挿入します。

挿入された要素の内容は、カーソルインターフェースを通じて確認できます。

2 つ目の関数グループは、ドキュメントに構造を与える要素を挿入し、挿入された構造を返します。

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

カーソルは、新しいブロックの先頭に配置されます。

フレーム

フレームはカーソルを使用してドキュメントに挿入され、現在のブロックの後にカーソルの現在のフレーム内に配置されます。以下のコードは、ドキュメントのルートフレーム内の 2 つのテキストブロックの間にフレームを挿入する方法を示しています。まず、カーソルの現在のフレームを特定します。

    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 クラスを使用して、プログラムでドキュメントを編集できます。このクラスは画面カーソルをモデルにしており、編集操作も同様のセマンティクスに従います。次のコードは、ドキュメントの 1 行目を太字に変更し、その他のフォントプロパティは変更しません。 エディタは、基となるドキュメントデータに加えられた変更を反映するように自動的に更新されます。

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

カーソルが1行目の先頭から末尾へ移動したものの、行の先頭にはアンカーが残っている点に注意してください。これは、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.