日本語で学ぶ Qt QPlainTextEdit 文字スタイル取得の基本 (currentCharFormat)

2025-03-21

QPlainTextEdit::currentCharFormat() とは

QPlainTextEdit::currentCharFormat() は、Qtのテキスト編集ウィジェットである QPlainTextEdit クラスのメンバ関数の一つです。この関数は、現在カーソルがある位置の文字(または選択範囲がある場合は選択範囲の最初の文字)に適用されているテキストフォーマットを返します。

具体的には、フォントの種類、フォントサイズ、太字、斜体、下線、文字色、背景色など、テキストの見た目に関する様々な属性を含む QTextCharFormat オブジェクトを返します。

  • 引数
    なし
  • 戻り値
    QTextCharFormat オブジェクト (現在の文字フォーマット)
  • 関数名
    currentCharFormat()
  • クラス
    QPlainTextEdit

どのような時に使うのか

QPlainTextEdit::currentCharFormat() は、以下のような場合に役立ちます。

  1. 現在のカーソル位置のフォーマット情報を取得したい場合
    例えば、ユーザーがテキストを入力する際に、現在のフォーマットを維持したい場合や、現在のフォーマットを表示したい場合などに使用します。

  2. 選択範囲の最初の文字のフォーマット情報を取得したい場合
    選択範囲がある状態でこの関数を呼び出すと、選択範囲の開始位置にある文字のフォーマットが返されます。

  3. テキストエディタのフォーマット関連機能の実装
    リッチテキストエディタのような、文字のスタイルを変更できる機能を作成する際に、現在のフォーマットを取得して、新しいフォーマットを適用する際の基準として利用できます。

使用例 (C++ コード)

#include <QApplication>
#include <QPlainTextEdit>
#include <QFont>
#include <QColor>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QPlainTextEdit plainTextEdit;
    plainTextEdit.setPlainText("Hello, Qt!");

    // カーソルを先頭に移動
    QTextCursor cursor = plainTextEdit.textCursor();
    cursor.setPosition(0);
    plainTextEdit.setTextCursor(cursor);

    // 現在の文字フォーマットを取得
    QTextCharFormat currentFormat = plainTextEdit.currentCharFormat();

    // フォーマット情報を出力
    qDebug() << "Font Family:" << currentFormat.font().family();
    qDebug() << "Font Size:" << currentFormat.font().pointSize();
    qDebug() << "Font Weight:" << currentFormat.font().weight();
    qDebug() << "Foreground Color:" << currentFormat.foreground().color();
    qDebug() << "Background Color:" << currentFormat.background().color();

    // 新しいフォーマットを作成して適用
    QTextCharFormat newFormat;
    QFont boldFont = currentFormat.font();
    boldFont.setBold(true);
    newFormat.setFont(boldFont);
    newFormat.setForeground(Qt::red);

    // カーソルを移動して新しいフォーマットを適用
    cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 5); // "Hello" を選択
    cursor.mergeCharFormat(newFormat);
    plainTextEdit.setTextCursor(cursor);

    plainTextEdit.show();
    return a.exec();
}

コードの説明

  1. QPlainTextEdit のインスタンスを作成し、テキストを設定しています。
  2. カーソルを先頭に移動しています。
  3. currentCharFormat() を呼び出して、現在の文字フォーマットを取得しています。
  4. 取得したフォーマットから、フォントファミリー、サイズ、太さ、前景色、背景色などの情報を qDebug() で出力しています。
  5. 新しい QTextCharFormat オブジェクトを作成し、フォントを太字にし、前景色を赤に設定しています。
  6. カーソルを右に5文字移動させ("Hello" を選択)、mergeCharFormat() を使用して新しいフォーマットを選択範囲に適用しています。

この例からわかるように、currentCharFormat() は現在のテキストのスタイル情報を取得し、それを基に新しいスタイルを適用したり、情報を表示したりする際に非常に役立ちます。



QPlainTextEdit::currentCharFormat() に関連する一般的なエラーとトラブルシューティング

QPlainTextEdit::currentCharFormat() 自体は値を返す関数であり、直接的なエラーを引き起こすことは少ないですが、その使い方や関連する処理においていくつかの一般的な問題が発生する可能性があります。

カーソル位置が意図しない場所にある

  • トラブルシューティング
    • 関数を呼び出す前に QPlainTextEdit::textCursor() で現在のカーソルを取得し、QTextCursor::position()QTextCursor::selectionStart(), QTextCursor::selectionEnd() などでカーソル位置や選択範囲を確認する。
    • 必要に応じて QTextCursor::setPosition()QPlainTextEdit::setTextCursor() を使用して、カーソルを目的の位置に移動させる。
  • 原因
    • 関数を呼び出す前に、カーソルが意図した場所に移動していない。
    • 選択範囲が存在する場合、currentCharFormat() は選択範囲の最初の文字のフォーマットを返すため、期待する範囲のフォーマットではない可能性がある。
  • エラー
    currentCharFormat() が期待する位置のフォーマットを返さない。

フォーマットが期待通りに取得できない

  • トラブルシューティング
    • 問題が発生しているテキストの特定の位置で、実際にどのようなフォーマットが適用されているかを目視で確認する。
    • フォーマットが適用される処理と currentCharFormat() を呼び出す処理の順序を確認する。
    • フォーマットを変更する可能性のある他のコード部分を確認し、意図しない変更がないか調査する。
    • デバッガを使用して、currentCharFormat() が返す QTextCharFormat オブジェクトの内容を詳細に確認する。
  • 原因
    • テキストに複数の異なるフォーマットが適用されている場合、currentCharFormat() はあくまでカーソル位置(または選択範囲の先頭)のフォーマットを返す。
    • フォーマットが適用されたタイミングと currentCharFormat() を呼び出すタイミングがずれている。
    • 他の処理によって意図せずフォーマットが変更されている。
  • エラー
    currentCharFormat() が返す QTextCharFormat オブジェクトが、実際に適用されているはずのフォーマットと異なる。

取得したフォーマットの利用に関する問題

  • トラブルシューティング
    • 取得した QTextCharFormat オブジェクトの内容を確認し、必要な属性だけを新しい QTextCharFormat オブジェクトにコピーして使用する。
    • 新しいテキストを挿入する際に、QTextCursor の適切なメソッドを使用してフォーマットを適用する。例えば、QTextCursor::insertText(const QString &text, const QTextCharFormat &format) を使用するか、挿入後に QTextCursor::mergeCharFormat(const QTextCharFormat &format) を使用する。
  • 原因
    • QTextCharFormat オブジェクトは、様々な属性(フォント、色、装飾など)を持つため、必要な属性だけをコピーまたは適用する必要がある。単純にオブジェクト全体を適用すると、意図しない属性まで影響を与える可能性がある。
    • 新しいテキストを挿入する際に、適切な方法でフォーマットを適用していない (QTextCursor::insertText() にフォーマットを指定する、QTextCursor::mergeCharFormat() を使用するなど)。
  • エラー
    currentCharFormat() で取得した QTextCharFormat オブジェクトを使用して、新しいテキストに同じフォーマットを適用しようとしても、期待通りにならない。

シグナルとスロットの連携における問題

  • トラブルシューティング
    • QObject::connect() を使用して、シグナルとスロットが正しく接続されているか確認する。
    • スロット内で取得したフォーマット情報を、UIの適切な場所に反映する処理(例えば、ツールバーのボタンの状態を変更するなど)が正しく実装されているか確認する。
  • 原因
    • QPlainTextEdit のシグナル(例えば cursorPositionChanged())が正しくスロットに接続されていない。
    • スロット内で currentCharFormat() を呼び出しているが、その結果をUIに反映する処理が正しく実装されていない。
  • エラー
    カーソル位置が変更された際に currentCharFormat() を呼び出してフォーマットを更新しようとしても、期待通りに動作しない。

パフォーマンスに関する考慮事項

  • 対策
    • 不必要に頻繁な呼び出しを避ける。
    • フォーマット情報の更新が必要な場合にのみ呼び出すようにする。
  • 問題
    cursorPositionChanged() シグナルなどで頻繁に currentCharFormat() を呼び出すと、パフォーマンスに影響が出る可能性がある。
  • ログ出力
    重要な処理の前後でログを出力し、処理の流れや変数の変化を追跡します。
  • ブレークポイントの設定
    問題が発生していると思われる箇所にブレークポイントを設定し、プログラムの実行を一時停止させて変数の状態などを確認します。
  • qDebug() の活用
    currentCharFormat() が返す QTextCharFormat オブジェクトの内容(フォントファミリー、サイズ、太字などの属性)を qDebug() で出力して確認することで、何が取得されているかを把握できます。


例1: 現在のカーソル位置のフォント情報を表示する

この例では、QPlainTextEdit 内のカーソル位置が変更されるたびに、その位置の文字のフォントファミリーとフォントサイズをコンソールに出力します。

#include <QApplication>
#include <QPlainTextEdit>
#include <QFont>
#include <QDebug>

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
        plainTextEdit = new QPlainTextEdit(this);
        setCentralWidget(plainTextEdit);

        connect(plainTextEdit, &QPlainTextEdit::cursorPositionChanged,
                this, &MainWindow::onCursorPositionChanged);
    }

private slots:
    void onCursorPositionChanged() {
        QTextCharFormat currentFormat = plainTextEdit->currentCharFormat();
        QFont currentFont = currentFormat.font();

        qDebug() << "カーソル位置のフォントファミリー:" << currentFont.family();
        qDebug() << "カーソル位置のフォントサイズ:" << currentFont.pointSize();
    }

private:
    QPlainTextEdit *plainTextEdit;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

#include "main.moc"

説明

  1. MainWindow クラスは、QPlainTextEdit を中央ウィジェットとして持つメインウィンドウです。
  2. cursorPositionChanged() シグナルが QPlainTextEdit から発行されるたびに、onCursorPositionChanged() スロットが呼び出されます。
  3. onCursorPositionChanged() スロット内では、plainTextEdit->currentCharFormat() を呼び出して、現在のカーソル位置の文字フォーマット (QTextCharFormat オブジェクト) を取得します。
  4. 取得した QTextCharFormat オブジェクトから font() メソッドを呼び出して、現在のフォント (QFont オブジェクト) を取得します。
  5. QFont オブジェクトの family()pointSize() メソッドを使用して、フォントファミリーとフォントサイズを取得し、qDebug() でコンソールに出力します。

例2: 現在のカーソル位置の文字色をボタンのスタイルシートに反映する

この例では、QPlainTextEdit 内のカーソル位置の文字色が変更されるたびに、ボタンのテキストの色を同じ色に設定します。

#include <QApplication>
#include <QMainWindow>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QHBoxLayout>
#include <QWidget>
#include <QColor>
#include <QDebug>

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
        plainTextEdit = new QPlainTextEdit(this);
        button = new QPushButton("テストボタン", this);

        QWidget *centralWidget = new QWidget;
        QHBoxLayout *layout = new QHBoxLayout(centralWidget);
        layout->addWidget(plainTextEdit);
        layout->addWidget(button);
        setCentralWidget(centralWidget);

        connect(plainTextEdit, &QPlainTextEdit::cursorPositionChanged,
                this, &MainWindow::onCursorPositionChanged);
    }

private slots:
    void onCursorPositionChanged() {
        QTextCharFormat currentFormat = plainTextEdit->currentCharFormat();
        QColor textColor = currentFormat.foreground().color();

        QString styleSheet = QString("color: %1;").arg(textColor.name());
        button->setStyleSheet(styleSheet);
    }

private:
    QPlainTextEdit *plainTextEdit;
    QPushButton *button;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

#include "main.moc"

説明

  1. MainWindow クラスは、QPlainTextEditQPushButton を持つメインウィンドウです。
  2. cursorPositionChanged() シグナルが発行されるたびに、onCursorPositionChanged() スロットが呼び出されます。
  3. onCursorPositionChanged() スロット内では、現在の文字フォーマットを取得し、foreground() メソッドで前景色 (QBrush オブジェクト) を取得します。
  4. QBrush オブジェクトから color() メソッドを呼び出して、文字色 (QColor オブジェクト) を取得します。
  5. 取得した QColor オブジェクトの name() メソッドを使用して、色の16進数表現の文字列を取得し、それをボタンのスタイルシートの color プロパティに設定します。これにより、ボタンのテキストの色が現在のカーソル位置の文字色と一致します。

例3: 選択範囲の最初の文字の太字属性をチェックする

この例では、QPlainTextEdit でテキストが選択されたときに、選択範囲の最初の文字が太字かどうかをチェックし、結果をコンソールに出力します。

#include <QApplication>
#include <QPlainTextEdit>
#include <QTextCursor>
#include <QFont>
#include <QDebug>

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
        plainTextEdit = new QPlainTextEdit(this);
        plainTextEdit->setPlainText("通常のテキスト\n<b>太字のテキスト</b>");
        setCentralWidget(plainTextEdit);

        connect(plainTextEdit, &QPlainTextEdit::selectionChanged,
                this, &MainWindow::onSelectionChanged);
    }

private slots:
    void onSelectionChanged() {
        QTextCursor cursor = plainTextEdit->textCursor();
        if (cursor.hasSelection()) {
            QTextCharFormat currentFormat = plainTextEdit->currentCharFormat();
            QFont currentFont = currentFormat.font();
            bool isBold = currentFont.bold();

            qDebug() << "選択範囲の最初の文字は太字ですか?:" << (isBold ? "はい" : "いいえ");
        }
    }

private:
    QPlainTextEdit *plainTextEdit;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

#include "main.moc"
  1. MainWindow クラスは、QPlainTextEdit を持つメインウィンドウです。初期テキストとして、通常のテキストと <b> タグで囲まれた太字のテキストを設定しています。
  2. selectionChanged() シグナルが QPlainTextEdit から発行されるたびに、onSelectionChanged() スロットが呼び出されます。
  3. onSelectionChanged() スロット内では、まず plainTextEdit->textCursor() で現在のテキストカーソルを取得し、cursor.hasSelection() で何らかのテキストが選択されているかどうかを確認します。
  4. 選択されている場合、plainTextEdit->currentCharFormat() を呼び出して、選択範囲の最初の文字のフォーマットを取得します。
  5. 取得したフォーマットからフォントを取得し、font().bold() メソッドでそのフォントが太字かどうかを判定します。
  6. 結果を qDebug() でコンソールに出力します。


QTextCursor を直接操作する

QPlainTextEdit のテキスト操作は主に QTextCursor クラスを通じて行われます。QTextCursor は、カーソル位置や選択範囲に関する情報を持つだけでなく、テキストの挿入や削除、フォーマットの適用といった操作も可能です。

  • 特定の範囲のフォーマットを取得・設定する
    QTextCursorsetPosition()movePosition() などを利用してカーソルの位置や範囲を操作し、その範囲に対して charFormat()setCharFormat() を使用することで、currentCharFormat() が対象とするカーソル位置だけでなく、任意の範囲のフォーマットを操作できます。

  • 選択範囲全体のフォーマットを扱う
    currentCharFormat() は選択範囲の最初の文字のフォーマットしか返しませんが、QTextCursor を使用すると、選択範囲全体にわたるフォーマットを調べたり、適用したりできます。例えば、選択範囲内のすべての文字が同じフォーマットを持っているか確認したり、異なるフォーマットが混在している場合に特定の処理を行ったりできます。

    QTextCursor cursor = plainTextEdit->textCursor();
    if (cursor.hasSelection()) {
        int start = cursor.selectionStart();
        int end = cursor.selectionEnd();
        // 選択範囲内の各文字のフォーマットを調べるなどの処理
    }
    
  • 現在のカーソル位置のフォーマットを取得する
    QTextCursor オブジェクトを取得し、charFormat() メソッドを使用することで、currentCharFormat() と同様に現在の文字フォーマットを取得できます。

    QTextCursor cursor = plainTextEdit->textCursor();
    QTextCharFormat currentFormat = cursor.charFormat();
    

QTextEdit::textCharFormat() (リッチテキストの場合)

もし、より高度なリッチテキスト編集機能が必要な場合は、QPlainTextEdit ではなく QTextEdit を使用することを検討してください。QTextEdit は、画像やテーブルの埋め込み、より複雑なテキストフォーマットに対応しています。

QTextEdit クラスには textCharFormat() というメソッドがあり、これは currentCharFormat() と同様に現在のカーソル位置の文字フォーマットを返します。QTextEdit では、より豊富なフォーマットオプションが利用可能です。

スタイルシート (CSS) を利用する

QPlainTextEdit (および QTextEdit) は、基本的なテキストフォーマットに加えて、スタイルシート (CSS) をある程度サポートしています。スタイルシートを使用すると、テキストの見た目をより柔軟に制御できます。

  • HTML サブセットの利用
    QPlainTextEdit::setHtml() を使用して、HTML のサブセットを含むテキストを設定できます。HTML タグを使用して、テキストの一部に異なるフォーマットを適用できます。この場合、currentCharFormat() はカーソル位置の HTML スタイルに対応する QTextCharFormat を返します。

  • 全体的なスタイルの設定
    QPlainTextEdit::setStyleSheet() を使用して、ウィジェット全体のフォント、色、背景などを設定できます。これは、特定のテキスト範囲のフォーマットを動的に変更する currentCharFormat() とは異なりますが、一貫したスタイルを適用するのに役立ちます。

テキスト属性を直接管理するモデル/ビューアーキテクチャ

より複雑なテキスト処理や、テキストの表示とデータの管理を分離したい場合には、Qt のモデル/ビューアーキテクチャの利用を検討できます。

  • カーソル位置や選択範囲が変更された際に、ビューからモデルに問い合わせて現在のフォーマット情報を取得したり、モデルを通じてフォーマットを更新したりします。
  • QPlainTextEdit (または QTextEdit) をビューとして使用し、モデルのデータに基づいてテキストを表示します。
  • テキストデータをモデル (例えば、独自のデータ構造や QAbstractItemModel を継承したクラス) に格納し、各文字やテキストブロックに関連する属性 (フォーマット情報など) をモデル内で管理します。

この方法は、より高度なカスタマイズや、大規模なテキストデータを扱う場合に有効ですが、実装の複雑さは増します。

カスタムテキスト編集ウィジェットを作成する

特定の高度な要求がある場合は、QPlainTextEditQTextEdit を直接使用するのではなく、QWidget を継承して独自のテキスト編集ウィジェットを作成することも可能です。この場合、テキストの描画、カーソルの管理、フォーマットの処理などを完全に自力で実装する必要がありますが、非常に高い柔軟性が得られます。

どのような代替手法を選ぶべきか

  • 非常に特殊な要件がある
    カスタムテキスト編集ウィジェットの作成を検討します。
  • テキストデータと表示を分離したい、複雑なテキスト処理を行いたい
    モデル/ビューアーキテクチャを検討します。
  • HTML 形式のテキストを扱いたい
    setHtml() を使用します。
  • ウィジェット全体の基本的なスタイルを適用したい
    スタイルシート (setStyleSheet()) を使用します。
  • より高度なリッチテキスト機能が必要
    QTextEdit とその関連メソッドを使用します。
  • 選択範囲全体のフォーマットを扱いたい
    QTextCursor の選択範囲操作とフォーマット関連メソッドを組み合わせます。
  • 現在のカーソル位置のフォーマット取得が主な目的
    QTextCursor::charFormat()currentCharFormat() の直接的な代替となります。