Qt開発Tips: QTextEditでリッチテキスト/プレーンテキストを動的に切り替える

2025-05-27

QTextEdit::acceptRichText

QTextEdit クラスにおける acceptRichText 関数は、テキストエディットがリッチテキスト形式のテキスト(例えば、HTMLのような装飾情報を含むテキスト)をどのように扱うかを制御するための関数です。

具体的には、この関数が true (デフォルト値) に設定されている場合、QTextEdit は外部からペーストされたり、プログラムによって設定されたテキストがリッチテキスト形式であると解釈し、その装飾情報を保持して表示します。

一方、この関数が false に設定されている場合、QTextEdit は入力されたテキストをプレーンテキストとして扱い、リッチテキスト形式の装飾情報は無視されます。つまり、太字や斜体、色などの情報は失われ、ただの文字の並びとして表示されます。

どのような時に使うか

  • プレーンテキストのみを扱いたい場合
    例えば、ユーザーに単純なテキストを入力させたい場合や、リッチテキストの装飾を意図的に取り除きたい場合には、acceptRichText(false) を呼び出して設定します。これにより、ユーザーがリッチテキストをペーストしても、装飾のないテキストとして扱われます。

  • リッチテキストを扱いたい場合
    ユーザーがコピー&ペーストで装飾されたテキストを入力したり、プログラム側でHTMLなどのリッチテキスト形式のデータを表示したり編集させたい場合には、acceptRichTexttrue のままにしておくのが一般的です。

#include <QApplication>
#include <QTextEdit>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTextEdit textEditRich;
    textEditRich.setPlainText("This is <b>bold</b> and <i>italic</i> text.");
    textEditRich.setWindowTitle("Accepts Rich Text (Default)");
    textEditRich.show();

    QTextEdit textEditPlain;
    textEditPlain.setAcceptRichText(false);
    textEditPlain.setPlainText("This is <b>bold</b> and <i>italic</i> text.");
    textEditPlain.setWindowTitle("Accepts Plain Text Only");
    textEditPlain.show();

    return a.exec();
}

上記の例では、二つの QTextEdit ウィジェットを作成しています。

  • textEditPlainsetAcceptRichText(false) を呼び出しているため、同じ HTML タグを含むテキストを設定しても、タグは無視され、プレーンなテキストとして表示されます。
  • textEditRich はデフォルト設定のままなので、setPlainText で設定された HTML タグ (<b>, <i>) が解釈され、テキストは太字と斜体で表示されます。


QTextEdit::acceptRichText 関連の一般的なエラーとトラブルシューティング

意図せずリッチテキストが無視される

  • トラブルシューティング
    • コード内で setAcceptRichText(false) を呼び出している箇所がないか確認してください。
    • もし、リッチテキストを扱いたい場合は、この呼び出しを削除するか、setAcceptRichText(true) に変更してください(デフォルトは true です)。
    • 他の場所で acceptRichText の設定が上書きされていないか確認してください。
  • 原因
    acceptRichText(false) を誤って設定してしまっている。

意図せずプレーンテキストとして扱われる

  • トラブルシューティング
    • 設定しているテキストデータが正しいリッチテキスト形式(例えば、有効な HTML サブセット)であることを確認してください。
    • プログラムでリッチテキストを生成している場合は、生成ロジックに誤りがないか確認してください。
    • 外部ファイルからリッチテキストを読み込んでいる場合は、ファイルの内容が破損していないか、エンコーディングが適切かなどを確認してください。
  • 原因
    リッチテキスト形式のデータが正しくない形式で QTextEdit に渡されている。例えば、HTMLのタグが閉じられていない、特殊文字がエスケープされていないなど。

コピー&ペーストでリッチテキストが失われる

  • トラブルシューティング
    • 他のリッチテキストエディタ(例えば、OS標準のテキストエディタなど)との間でコピー&ペーストを試し、同様の問題が発生するか確認してください。もし他のエディタでも問題がある場合は、コピー元のアプリケーションやOSのクリップボード機能に問題がある可能性があります。
    • QTextEdit の基本的なコピー&ペースト機能を使用しているか確認してください。カスタムのクリップボード操作を行っている場合は、その部分のコードを見直してください。
  • 原因
    • コピー元のアプリケーションが提供するリッチテキスト形式が、QTextEdit が対応していない形式である可能性があります。
    • QTextEdit が配置されている環境(OSやクリップボードマネージャーなど)の影響を受けている可能性もあります。
    • プログラム内でクリップボード操作を独自に実装している場合、その実装に問題があるかもしれません。

パフォーマンスの問題

  • トラブルシューティング
    • もし可能であれば、表示するリッチテキストデータのサイズを小さくしたり、装飾を簡略化したりすることを検討してください。
    • 必要に応じて、リッチテキストを複数の小さなチャンクに分割して段階的に表示することを検討してください。
    • プレーンテキストで十分な場合は、acceptRichText(false) を設定し、プレーンテキストとして処理することでパフォーマンスが向上する可能性があります。
  • 原因
    非常に大きなリッチテキストデータを QTextEdit に表示しようとしている。複雑な装飾が多いリッチテキストも描画に時間がかかることがあります。

予期しない表示

  • トラブルシューティング
    • QTextEdit::setStyleSheet() で設定しているスタイルシートの内容を確認し、意図しないスタイルが適用されていないか確認してください。
    • リッチテキスト自体に含まれるスタイル情報と、適用されているスタイルシートが競合していないか確認してください。
  • 原因
    CSS スタイルシートが適用されている場合、そのスタイルがリッチテキストの表示に影響を与えている可能性があります。
  • Qt のドキュメントを参照する
    QTextEdit クラスや関連するクラス(QTextDocumentQClipboard など)の公式ドキュメントを参照し、各機能の詳細な仕様や注意点を確認してください。
  • シンプルな例で試す
    問題が複雑な場合に、最小限のコードで acceptRichText の動作を確認するテストプログラムを作成し、挙動を理解することから始めるのが有効です。
  • テキストの内容をログ出力する
    QTextEdit::toHtml()QTextEdit::toPlainText() を使用して、実際に QTextEdit が保持しているテキストの内容をログに出力し、期待通りの形式になっているか確認すると問題の切り分けに役立ちます。


#include <QApplication>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QWidget>

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

    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    QTextEdit *richTextEdit = new QTextEdit();
    richTextEdit->setHtml("<p>This is <b>bold</b> text.</p>"
                         "<p>This is <font color='blue'>blue</font> text.</p>");
    layout->addWidget(richTextEdit);

    window.setLayout(layout);
    window.setWindowTitle("Accepts Rich Text (Default)");
    window.show();

    return a.exec();
}

説明

  • acceptRichText はデフォルトで true なので、QTextEdit はこの HTML タグを解釈し、太字や青色のテキストとして表示します。
  • このコードは、QTextEdit ウィジェットを作成し、HTML形式のテキスト (<p>, <b>, <font>) を setHtml() 関数を使って設定しています。

この例では、acceptRichText(false) を明示的に呼び出すことで、QTextEdit がリッチテキスト形式の装飾を無視し、プレーンテキストとして扱います。

#include <QApplication>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QWidget>

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

    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    QTextEdit *plainTextEdit = new QTextEdit();
    plainTextEdit->setAcceptRichText(false);
    plainTextEdit->setHtml("<p>This is <b>bold</b> text.</p>"
                          "<p>This is <font color='blue'>blue</font> text.</p>");
    layout->addWidget(plainTextEdit);

    window.setLayout(layout);
    window.setWindowTitle("Accepts Plain Text Only");
    window.show();

    return a.exec();
}

説明

  • その結果、setHtml() で HTML 形式のテキストを設定していますが、QTextEdit はこれをプレーンテキストとして扱い、<p>This is <b>bold</b> text.</p><p>This is <font color='blue'>blue</font> text.</p> のように、タグも含めてそのまま表示します。
  • ここでは、plainTextEdit->setAcceptRichText(false); を呼び出すことで、acceptRichTextfalse に設定しています。

この例は、ユーザーが外部のアプリケーションからテキストをコピー&ペーストする際の挙動を示しています。

#include <QApplication>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QWidget>

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

    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    // リッチテキストを受け入れる QTextEdit (デフォルト)
    QTextEdit *richTextEdit = new QTextEdit();
    richTextEdit->setPlainText("Try pasting rich text here (e.g., from a web browser).");
    layout->addWidget(richTextEdit);

    // プレーンテキストのみを受け入れる QTextEdit
    QTextEdit *plainTextEdit = new QTextEdit();
    plainTextEdit->setAcceptRichText(false);
    plainTextEdit->setPlainText("Try pasting text here. Formatting will be lost.");
    layout->addWidget(plainTextEdit);

    window.setLayout(layout);
    window.setWindowTitle("AcceptRichText Example");
    window.show();

    return a.exec();
}

説明

  • 下側の plainTextEditacceptRichText(false) が設定されているため、同じように装飾されたテキストをペーストしても、装飾は取り除かれ、プレーンなテキストとして表示されます。
  • 上側の richTextEdit はデフォルト設定(acceptRichTexttrue)なので、例えばウェブブラウザから装飾されたテキストをコピーしてペーストすると、その装飾(太字、色など)が保持されて表示されます。
  • このコードでは、二つの QTextEdit ウィジェットを作成しています。

この例では、ボタンを使って実行中に acceptRichText の設定を切り替える方法を示します。

#include <QApplication>
#include <QTextEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>

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

    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    QTextEdit *textEdit = new QTextEdit();
    textEdit->setHtml("<p>This text can change its behavior.</p>"
                     "<p>Try pasting rich text after toggling the setting.</p>");
    layout->addWidget(textEdit);

    QPushButton *toggleButton = new QPushButton("Toggle Accept Rich Text");
    layout->addWidget(toggleButton);

    bool acceptRich = true;
    QObject::connect(toggleButton, &QPushButton::clicked, [&]() {
        acceptRich = !acceptRich;
        textEdit->setAcceptRichText(acceptRich);
        if (acceptRich) {
            toggleButton->setText("Toggle Accept Rich Text (Currently ON)");
        } else {
            toggleButton->setText("Toggle Accept Rich Text (Currently OFF)");
        }
    });
    toggleButton->setText("Toggle Accept Rich Text (Currently ON)");

    window.setLayout(layout);
    window.setWindowTitle("Toggling AcceptRichText");
    window.show();

    return a.exec();
}
  • この例を実行し、ボタンをクリックして acceptRichText の状態を切り替えながら、リッチテキストをペーストしたり、setHtml() でリッチテキストを設定したりすることで、挙動の変化を確認できます。
  • ボタンのテキストも、現在の acceptRichText の状態に応じて更新されます。
  • ボタンがクリックされると、ラムダ式を使って acceptRich 変数の値を反転させ、その新しい値を textEdit->setAcceptRichText() に設定します。
  • このコードでは、QTextEditQPushButton を配置しています。


イベントフィルタリングによる制御

QTextEdit にイベントフィルタをインストールすることで、テキストが挿入される前の段階で内容を検査し、リッチテキストの装飾を取り除くことができます。

#include <QApplication>
#include <QTextEdit>
#include <QKeyEvent>
#include <QEvent>
#include <QClipboard>
#include <QMimeData>
#include <QTextCursor>

class PlainTextFilter : public QObject
{
public:
    PlainTextFilter(QObject *parent = nullptr) : QObject(parent) {}

protected:
    bool eventFilter(QObject *watched, QEvent *event) override
    {
        if (event->type() == QEvent::KeyPress) {
            QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
            if ((keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key() == Qt::Key_V) {
                // Ctrl+V (ペースト) イベントを捕捉
                QClipboard *clipboard = QApplication::clipboard();
                const QMimeData *mimeData = clipboard->mimeData();
                if (mimeData->hasHtml()) {
                    // クリップボードに HTML が含まれている場合、プレーンテキストのみを取得して挿入
                    QTextCursor cursor = static_cast<QTextEdit *>(watched)->textCursor();
                    cursor.insertText(mimeData->text());
                    return true; // イベントを処理済みとして伝播を防ぐ
                }
            }
        }
        return QObject::eventFilter(watched, event);
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTextEdit textEdit;
    PlainTextFilter *filter = new PlainTextFilter(&textEdit);
    textEdit.installEventFilter(filter);
    textEdit.setPlainText("Paste text here (rich text will be converted to plain text on paste).");
    textEdit.setWindowTitle("Event Filter for Plain Text");
    textEdit.show();
    return a.exec();
}

説明

  • この方法では、acceptRichTexttrue のままにしていても、ペースト時にリッチテキストが自動的にプレーンテキストに変換されます。
  • return true; を返すことで、元のペースト処理が行われるのを防ぎます。
  • クリップボードの内容が HTML 形式の場合、mimeData()->text() を使ってプレーンテキストを取得し、カーソル位置に挿入します。
  • eventFilter 内で QEvent::KeyPress イベントを監視し、特に Ctrl+V (ペースト) のキーイベントを捕捉します。
  • PlainTextFilter クラスは QObject を継承し、eventFilter 関数をオーバーライドしています。

QTextDocument の利用

QTextEdit は内部的に QTextDocument を使用してテキストを管理しています。QTextDocument を直接操作することで、より細かくテキストのフォーマットや内容を制御できます。

#include <QApplication>
#include <QTextEdit>
#include <QTextDocument>
#include <QTextCursor>
#include <QVBoxLayout>
#include <QWidget>

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

    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    QTextEdit *textEdit = new QTextEdit();
    QTextDocument *document = new QTextDocument();
    textEdit->setDocument(document);

    // リッチテキスト形式の文字列
    QString richText = "<p>This is <b>bold</b> and <i>italic</i> text.</p>";

    // QTextCursor を使ってドキュメントにプレーンテキストとして挿入
    QTextCursor cursor(document);
    cursor.insertText(richText); // HTML タグはそのまま文字列として挿入される

    layout->addWidget(textEdit);
    window.setLayout(layout);
    window.setWindowTitle("Using QTextDocument for Plain Text");
    window.show();

    return a.exec();
}

説明

  • この方法を使うと、acceptRichText の設定に関わらず、特定のテキストを常にプレーンテキストとして扱うことができます。
  • insertText() はテキストをプレーンテキストとして挿入するため、HTML タグは解釈されずにそのまま表示されます。
  • リッチテキスト形式の文字列 (richText) を QTextCursor::insertText() を使ってドキュメントに挿入しています。
  • この例では、QTextEdit に関連付ける QTextDocument を明示的に作成しています。

シグナルとスロットによる処理

QTextEdit から送信されるシグナル(例えば、textChanged() など)を捕捉し、テキストが変更された後に不要なリッチテキストの装飾をプログラム側で削除することができます。

#include <QApplication>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QWidget>

class MainWindow : public QWidget
{
public:
    MainWindow(QWidget *parent = nullptr) : QWidget(parent)
    {
        textEdit = new QTextEdit();
        layout = new QVBoxLayout(this);
        layout->addWidget(textEdit);
        setWindowTitle("Signal-Based Plain Text");

        connect(textEdit, &QTextEdit::textChanged, this, &MainWindow::convertToPlainText);
    }

private slots:
    void convertToPlainText()
    {
        // 現在のカーソル位置と選択範囲を保存
        QTextCursor cursor = textEdit->textCursor();
        int position = cursor.position();

        // ドキュメント全体をプレーンテキストとして取得し再設定
        QString plainText = textEdit->toPlainText();
        textEdit->setPlainText(plainText);

        // カーソル位置を復元
        QTextCursor newCursor = textEdit->textCursor();
        newCursor.setPosition(position);
        textEdit->setTextCursor(newCursor);
    }

private:
    QTextEdit *textEdit;
    QVBoxLayout *layout;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow window;
    window.show();
    return a.exec();
}
  • この方法は、ユーザーがリッチテキストをペーストしたり入力したりした後に、自動的にプレーンテキストに変換したい場合に有効です。
  • カーソル位置を保存・復元することで、テキストが変更されてもユーザーの入力位置が維持されるように配慮しています。
  • convertToPlainText() スロットでは、現在のテキストエディットの内容を toPlainText() でプレーンテキストとして取得し、setPlainText() で再設定します。これにより、リッチテキストの装飾が失われます。
  • MainWindow クラスは QTextEdit を含み、textChanged() シグナルが発行されるたびに convertToPlainText() スロットを呼び出します。