Qt GUI プログラミング QPlainTextEdit マウスイベント

2025-04-26

Qt プログラミングにおける QPlainTextEdit クラスは、複数行のテキストを表示および編集するためのウィジェットです。mousePressEvent() は、この QPlainTextEdit ウィジェット内でマウスボタンが押されたときに発生するイベントを処理するために使用される仮想関数です。

基本的な役割

mousePressEvent() は、ユーザーが QPlainTextEdit ウィジェット上でマウスボタン(左、右、または中央)を押したときに呼び出されます。このイベントハンドラーをオーバーライドすることで、マウスボタンの押下に対する独自の処理を実装できます。

イベントオブジェクト (QMouseEvent)

  • modifiers()
    Shift、Ctrl、Alt などの修飾キーの状態を返します。
  • buttons()
    現在押されているすべてのマウスボタンのビットマスクを返します。
  • button()
    押されたマウスボタンの種類(Qt::LeftButton, Qt::RightButton, Qt::MiddleButton など)を返します。
  • globalPos()
    マウスカーソルのグローバル画面座標を返します。
  • pos()
    マウスカーソルの位置(ウィジェットのローカル座標系における)を返します。

オーバーライドと実装

QPlainTextEdit をサブクラス化し、mousePressEvent() をオーバーライドすることで、特定のマウスボタンの押下に対するカスタム動作を実装できます。

#include <QPlainTextEdit>
#include <QMouseEvent>
#include <QDebug>

class MyPlainTextEdit : public QPlainTextEdit
{
public:
    MyPlainTextEdit(QWidget *parent = nullptr) : QPlainTextEdit(parent) {}

protected:
    void mousePressEvent(QMouseEvent *event) override
    {
        if (event->button() == Qt::LeftButton) {
            qDebug() << "左マウスボタンが押されました。位置: " << event->pos();
            // ここに左クリック時の独自の処理を記述
        } else if (event->button() == Qt::RightButton) {
            qDebug() << "右マウスボタンが押されました。位置: " << event->pos();
            // ここに右クリック時の独自の処理を記述
        } else if (event->button() == Qt::MiddleButton) {
            qDebug() << "中マウスボタンが押されました。位置: " << event->pos();
            // ここに中クリック時の独自の処理を記述
        }

        // デフォルトの処理も実行する場合は、親クラスの mousePressEvent を呼び出す
        QPlainTextEdit::mousePressEvent(event);
    }
};

上記の例では、MyPlainTextEdit クラスを定義し、mousePressEvent() をオーバーライドしています。左マウスボタンが押された場合はデバッグメッセージを出力し、右マウスボタンが押された場合は別のメッセージを出力します。最後に、QPlainTextEdit::mousePressEvent(event) を呼び出すことで、QPlainTextEdit のデフォルトの処理(例えば、カーソルの移動や選択など)も実行されます。

主な用途

  • ドラッグアンドドロップ操作の開始の検出。
  • コンテキストメニューの表示(通常は mouseReleaseEvent() で処理されますが、mousePressEvent() で初期化を行うこともあります)。
  • 特定の場所でのクリックに対する特別な処理。
  • 特定のマウスボタンのクリックに対するカスタムアクションの実行。
  • イベント処理を適切に行わないと、ユーザーインターフェースが期待通りに動作しなくなる可能性があります。
  • マウスイベントの処理をオーバーライドする場合は、必要に応じて親クラスのイベントハンドラーを呼び出すことを推奨します。これにより、QPlainTextEdit の基本的な動作を維持できます。
  • mousePressEvent() は、マウスボタンが押された瞬間に呼び出されます。ボタンが離されたときの処理は mouseReleaseEvent() で行います。


QPlainTextEdit::mousePressEvent() をオーバーライドして独自の処理を実装する際に、以下のような一般的なエラーが発生する可能性があります。また、それらのトラブルシューティング方法についても説明します。

イベントが正しく捕捉されない

  • トラブルシューティング

    • イベントフィルタの確認
      installEventFilter() を使用している場合は、フィルタ内でイベントが消費されていないか確認します。必要であれば、フィルタの優先順位を調整するか、フィルタを一時的に無効にして問題を切り分けます。
    • event->ignore() の確認
      mousePressEvent() 内で event->ignore() を使用している箇所がないか確認し、本当にその処理が必要かどうかを検討します。デフォルトの処理も実行したい場合は、event->accept() を呼び出す必要があります。
    • サブクラス化の確認
      サブクラスのヘッダーファイルと実装ファイルで、正しく QPlainTextEdit を継承し、mousePressEvent() をオーバーライドしているか確認します。また、サブクラスのインスタンスが正しく作成され、使用されているか確認します。
    • ウィジェットの可視性の確認
      ウィジェットが show() されているか、または親ウィジェットが表示されているかを確認します。
    • イベントフィルタの設定ミス
      ウィジェットやその親ウィジェットにイベントフィルタを設定しており、それが mousePressEvent() の前にイベントを消費している可能性があります。
    • event->ignore() の誤った使用
      mousePressEvent() 内で event->ignore() を呼び出すと、イベントが他のウィジェットや Qt のデフォルトの処理に伝播されなくなります。意図しない場所でこれを実行している可能性があります。
    • サブクラス化の誤り
      QPlainTextEdit を正しくサブクラス化していない、またはオーバーライドしたメソッドが正しく呼び出されていない可能性があります。
    • ウィジェットの可視性
      ウィジェットが非表示(isHidden()true)になっている場合、マウスイベントは発生しない可能性があります。

意図しない動作が発生する

  • トラブルシューティング

    • 親クラスのイベントハンドラーの呼び出し
      オーバーライドした mousePressEvent() の最後に必ず QPlainTextEdit::mousePressEvent(event) を呼び出すようにします。これにより、デフォルトの動作が維持されます。
    • マウスボタンと修飾キーの確認
      event->button()event->buttons()event->modifiers() を使用して、押されたボタンや修飾キーの状態を正しく判定しているか、qDebug() などでログを出力して確認します。
    • 座標系の理解
      event->pos() はウィジェットのローカル座標系、event->globalPos() は画面全体のグローバル座標系です。目的に応じて適切な座標系を使用しているか確認します。必要であれば、mapToGlobal()mapFromGlobal() などのメソッドを使用して座標を変換します。
  • 原因

    • デフォルトの処理の抑制
      オーバーライドした mousePressEvent() 内で、親クラスの QPlainTextEdit::mousePressEvent(event) を呼び出していない場合、カーソルの移動や選択など、QPlainTextEdit の基本的な動作が失われます。
    • イベント処理の誤り
      マウスボタンの種類(左、右、中央)や修飾キーの状態などを正しく判定できていない可能性があります。
    • 座標系の誤り
      event->pos() で取得したローカル座標系と、ウィンドウやグローバル座標系との混同があるかもしれません。

メモリリークやリソースの解放漏れ

  • トラブルシューティング

    • メモリ管理の確認
      new でメモリを割り当てた場合は、必ず対応する delete で解放するようにします。スマートポインタ(std::unique_ptrstd::shared_ptr)の使用を検討することも有効です。
    • リソースの解放
      取得したリソース(ファイル、ソケットなど)は、不要になった時点で必ず解放するようにします。
  • 原因

    • mousePressEvent() 内で動的にメモリを割り当てているにも関わらず、解放処理を適切に行っていない可能性があります。
    • 外部のリソース(ファイルハンドルなど)を mousePressEvent() 内で取得し、解放を忘れている可能性があります。

特定の状況での問題

  • トラブルシューティング

    • レイアウトの簡素化
      問題がレイアウトに関連している疑いがある場合は、一時的にレイアウトを簡素化して問題が再現するかどうかを確認します。
    • イベント処理の順序
      複数のイベントが同時に発生する場合は、イベント処理の順序を考慮し、必要に応じてイベントの処理を遅延させるなどの対策を検討します。
  • 原因

    • 複雑なレイアウト
      ウィジェットが複雑なレイアウトの中に配置されている場合、マウスイベントの伝播や処理が予期しない動作を引き起こすことがあります。
    • 他のイベントとの干渉
      他のイベント(例えば、キーボードイベントやタイマーイベント)と同時に処理が行われる際に、競合が発生することがあります。

デバッグ方法

  • 最小限の再現可能な例の作成
    問題が発生するコードを最小限の例に絞り込み、問題の原因を特定しやすくします。
  • ブレークポイントの設定
    デバッガを使用して、mousePressEvent() 内のコードにブレークポイントを設定し、変数の値をステップ実行しながら確認します。
  • qDebug() を使用したログ出力
    mousePressEvent() が呼び出されているか、押されたボタンの種類、カーソルの位置、修飾キーの状態などを qDebug() で出力して、イベントが正しく捕捉され、情報が正しく取得できているかを確認します。

一般的な注意点

  • イベントの伝播
    Qt のイベントシステムにおけるイベントの伝播の仕組みを理解しておくことは、イベント処理の問題を解決する上で役立ちます。
  • Qt ドキュメントの参照
    QMouseEvent クラスや QPlainTextEdit クラスのドキュメントを参照し、それぞれのメソッドの詳細な動作や使用方法を確認することが重要です。


例1:左クリックでカーソル位置を取得し、メッセージを表示

この例では、QPlainTextEdit 上で左マウスボタンが押されたときに、カーソルの現在の位置(行番号と列番号)を取得し、メッセージボックスで表示します。

#include <QApplication>
#include <QPlainTextEdit>
#include <QMouseEvent>
#include <QMessageBox>
#include <QDebug>

class MyPlainTextEdit : public QPlainTextEdit
{
public:
    MyPlainTextEdit(QWidget *parent = nullptr) : QPlainTextEdit(parent) {}

protected:
    void mousePressEvent(QMouseEvent *event) override
    {
        if (event->button() == Qt::LeftButton) {
            // マウスカーソルの位置を取得
            QPoint pos = event->pos();

            // 座標からテキスト内の位置(QTextCursor)を取得
            QTextCursor cursor = cursorForPosition(pos);

            // 行番号と列番号を取得
            int row = cursor.blockNumber() + 1; // 0始まりなので+1
            int column = cursor.positionInBlock() + 1;

            // メッセージボックスで表示
            QMessageBox::information(this, tr("マウス左クリック"),
                                     tr("左クリックされました。\n行: %1, 列: %2")
                                     .arg(row).arg(column));
        }

        // デフォルトの処理も実行
        QPlainTextEdit::mousePressEvent(event);
    }
};

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

    MyPlainTextEdit textEdit;
    textEdit.setPlainText("これはサンプルテキストです。\n2行目です。\n3行目です。");
    textEdit.setWindowTitle("QPlainTextEdit Mouse Press Example");
    textEdit.resize(400, 200);
    textEdit.show();

    return a.exec();
}

解説

  1. MyPlainTextEdit クラスの定義
    QPlainTextEdit を継承した MyPlainTextEdit クラスを作成します。
  2. mousePressEvent() のオーバーライド
    mousePressEvent() メソッドをオーバーライドして、左マウスボタンの押下イベントを処理します。
  3. ボタンの判定
    event->button() == Qt::LeftButton で、押されたボタンが左ボタンかどうかを確認します。
  4. マウスカーソル位置の取得
    event->pos() で、ウィジェット内でのマウスカーソルの位置(QPoint 型)を取得します。
  5. カーソルオブジェクトの取得
    cursorForPosition(pos) メソッドを使用して、指定された位置に対応する QTextCursor オブジェクトを取得します。QTextCursor は、テキスト内の特定の場所を表すために使用されます。
  6. 行番号と列番号の取得
    • cursor.blockNumber() は、カーソルが現在位置しているブロック(行)の番号(0始まり)を返します。+1 して1始まりの行番号に変換します。
    • cursor.positionInBlock() は、カーソルが現在のブロック内で何文字目にあるか(0始まり)を返します。+1 して1始まりの列番号に変換します。
  7. メッセージボックスの表示
    QMessageBox::information() を使用して、取得した行番号と列番号を含むメッセージを表示します。
  8. デフォルトの処理の呼び出し
    QPlainTextEdit::mousePressEvent(event) を最後に呼び出すことで、カーソルの移動や選択など、QPlainTextEdit のデフォルトの動作を維持します。

例2:右クリックでコンテキストメニューを表示

この例では、QPlainTextEdit 上で右マウスボタンが押されたときに、シンプルなコンテキストメニューを表示します。

#include <QApplication>
#include <QPlainTextEdit>
#include <QMouseEvent>
#include <QMenu>
#include <QAction>
#include <QDebug>

class MyPlainTextEditWithContextMenu : public QPlainTextEdit
{
public:
    MyPlainTextEditWithContextMenu(QWidget *parent = nullptr) : QPlainTextEdit(parent)
    {
        // コンテキストメニューのアクションを作成
        copyAction = new QAction(tr("コピー"), this);
        connect(copyAction, &QAction::triggered, this, &MyPlainTextEditWithContextMenu::copy);

        // メニューを作成
        contextMenu = new QMenu(this);
        contextMenu->addAction(copyAction);
    }

protected:
    void mousePressEvent(QMouseEvent *event) override
    {
        if (event->button() == Qt::RightButton) {
            // 右クリックされた位置でコンテキストメニューを表示
            contextMenu->popup(mapToGlobal(event->pos()));
        } else {
            // それ以外のボタンの場合はデフォルトの処理を実行
            QPlainTextEdit::mousePressEvent(event);
        }
    }

private:
    QMenu *contextMenu;
    QAction *copyAction;
};

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

    MyPlainTextEditWithContextMenu textEdit;
    textEdit.setPlainText("右クリックでコンテキストメニューが表示されます。");
    textEdit.setWindowTitle("QPlainTextEdit Context Menu Example");
    textEdit.resize(400, 150);
    textEdit.show();

    return a.exec();
}

解説

  1. コンテキストメニューとアクションの作成
    コンストラクタで、QMenu オブジェクトと、メニューに表示する QAction オブジェクトを作成します。ここでは「コピー」アクションを作成し、copy() スロットに接続しています。
  2. mousePressEvent() のオーバーライド
    右マウスボタンが押された場合に処理を行います。
  3. 右クリックの判定
    event->button() == Qt::RightButton で右ボタンの押下を判定します。
  4. コンテキストメニューの表示
    contextMenu->popup(mapToGlobal(event->pos())) を使用して、右クリックされた位置(event->pos() はローカル座標なので、mapToGlobal() でグローバル座標に変換)にコンテキストメニューを表示します。
  5. copy() スロットの実装
    簡略化のため、ここでは copy() スロットは空にしていますが、実際には選択されたテキストをクリップボードにコピーする処理を記述します。

例3:ダブルクリックで単語を選択

この例では、mousePressEvent()mouseReleaseEvent() を組み合わせて、ダブルクリックされた単語を選択する機能を実装します。

#include <QApplication>
#include <QPlainTextEdit>
#include <QMouseEvent>
#include <QDebug>

class MyPlainTextEditSelectWord : public QPlainTextEdit
{
public:
    MyPlainTextEditSelectWord(QWidget *parent = nullptr) : QPlainTextEdit(parent), lastPressPos(QPoint(-1, -1)) {}

protected:
    void mousePressEvent(QMouseEvent *event) override
    {
        if (event->button() == Qt::LeftButton) {
            QPoint currentPos = event->pos();
            if (lastPressPos == currentPos && (QDateTime::currentDateTime().msecsSinceEpoch() - lastPressTime.msecsSinceEpoch() < QApplication::doubleClickInterval())) {
                // ダブルクリックと判定
                QTextCursor cursor = cursorForPosition(currentPos);
                cursor.select(QTextCursor::WordUnderCursor);
                setTextCursor(cursor);
            } else {
                // シングルクリックまたは最初のクリック
                lastPressPos = currentPos;
                lastPressTime = QDateTime::currentDateTime();
                // デフォルトの処理も実行
                QPlainTextEdit::mousePressEvent(event);
            }
        } else {
            QPlainTextEdit::mousePressEvent(event);
        }
    }

private:
    QPoint lastPressPos;
    QDateTime lastPressTime;
};

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

    MyPlainTextEditSelectWord textEdit;
    textEdit.setPlainText("この文章で単語をダブルクリックすると選択されます。");
    textEdit.setWindowTitle("QPlainTextEdit Double Click Example");
    textEdit.resize(400, 100);
    textEdit.show();

    return a.exec();
}
  1. lastPressPos と lastPressTime の保持
    前回の左クリックの位置 (lastPressPos) と時間 (lastPressTime) を保持するためのメンバー変数を定義します。
  2. ダブルクリックの判定
    • 左クリックが押されたときに、現在のクリック位置が前回のクリック位置と同じであり、かつ現在の時間と前回のクリック時間の差が QApplication::doubleClickInterval() より小さい場合に、ダブルクリックと判断します。
  3. 単語の選択
    ダブルクリックと判定された場合、cursorForPosition() でカーソルを取得し、cursor.select(QTextCursor::WordUnderCursor) を使用してカーソル下の単語を選択し、setTextCursor() で選択を反映させます。
  4. シングルクリックの場合
    ダブルクリックでなければ、現在のクリック位置と時間を保存し、通常の mousePressEvent() を呼び出します。


イベントフィルタ (Event Filter) の使用

  • 実装例
  • デメリット
    • 少し複雑な設定
      イベントフィルタのインストールと実装には、少し手間がかかります。
    • イベントの消費
      イベントフィルタ内でイベントを消費(event->accept() を呼び出さない)すると、ターゲットオブジェクトはイベントを受け取らなくなります。
  • メリット
    • オブジェクトの変更を伴わない
      QPlainTextEdit のサブクラス化を行わずに、イベント処理を追加できます。
    • 複数のオブジェクトに対する共通の処理
      複数の QPlainTextEdit ウィジェットに対して、同じイベントフィルタを適用して一括で処理を行うことができます。
    • イベントの早期捕捉
      イベントがターゲットオブジェクトに到達する前に処理できるため、より柔軟な制御が可能です。
#include <QApplication>
#include <QPlainTextEdit>
#include <QMouseEvent>
#include <QDebug>

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

protected:
    bool eventFilter(QObject *watched, QEvent *event) override
    {
        if (watched == plainTextEdit && event->type() == QEvent::MouseButtonPress) {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
            if (mouseEvent->button() == Qt::RightButton) {
                qDebug() << "イベントフィルタで右クリックを捕捉しました。";
                // ここで右クリックの処理を行う
                return true; // イベントを消費する
            }
        }
        // 他のイベントはデフォルトの処理へ
        return QObject::eventFilter(watched, event);
    }

private:
    QPlainTextEdit *plainTextEdit;
};

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

    QPlainTextEdit *textEdit = new QPlainTextEdit();
    textEdit->setPlainText("イベントフィルタのサンプルテキスト");
    textEdit->setWindowTitle("QPlainTextEdit Event Filter Example");
    textEdit->resize(300, 150);
    textEdit->show();

    MyEventFilter *filter = new MyEventFilter(textEdit);
    filter->plainTextEdit = textEdit; // イベントフィルタ内で対象のウィジェットを参照できるようにする
    textEdit->installEventFilter(filter);

    return a.exec();
}

解説

  1. MyEventFilter クラスを作成し、QObject を継承します。
  2. eventFilter() メソッドをオーバーライドします。このメソッドは、監視対象のオブジェクトとイベントを受け取ります。
  3. watched == plainTextEdit && event->type() == QEvent::MouseButtonPress で、監視対象が plainTextEdit であり、イベントの種類がマウスボタン押下 (QEvent::MouseButtonPress) であることを確認します。
  4. static_cast<QMouseEvent*>(event) で、QEventQMouseEvent にキャストします。
  5. mouseEvent->button() == Qt::RightButton で、右マウスボタンが押されたかどうかを判定します。
  6. 右クリックの場合、qDebug() でメッセージを出力し、return true; を返してイベントを消費します。
  7. それ以外の場合は、return QObject::eventFilter(watched, event); を呼び出して、デフォルトの処理(または他のフィルタ)にイベントを渡します。
  8. main() 関数内で、QPlainTextEdit オブジェクトを作成し、installEventFilter() メソッドを使用してイベントフィルタをインストールします。

シグナルとスロットの利用(カスタムウィジェットの場合)

  • 実装例(簡略化):
  • デメリット
    • 少し手間が増える
      シグナルとスロットの定義と接続が必要になります。
    • ウィジェットの構造を変更する必要がある
      QPlainTextEdit を含むカスタムウィジェットを作成する必要があります。
  • メリット
    • 分離された処理
      イベント処理をカスタムウィジェット内に閉じ込め、外部のロジックをスロットで処理できるため、コードの可読性と保守性が向上します。
    • 再利用性
      カスタムウィジェットを他の場所で再利用しやすくなります。
#include <QApplication>
#include <QWidget>
#include <QPlainTextEdit>
#include <QMouseEvent>
#include <QDebug>

class MyCustomWidget : public QWidget
{
    Q_OBJECT

public:
    MyCustomWidget(QWidget *parent = nullptr) : QWidget(parent)
    {
        plainTextEdit = new QPlainTextEdit(this);
        QVBoxLayout *layout = new QVBoxLayout(this);
        layout->addWidget(plainTextEdit);
        setLayout(layout);
    }

    QPlainTextEdit* getPlainTextEdit() const { return plainTextEdit; }

signals:
    void rightButtonClicked(const QPoint &pos);

protected:
    void mousePressEvent(QMouseEvent *event) override
    {
        if (event->button() == Qt::RightButton) {
            emit rightButtonClicked(event->pos());
        }
        QWidget::mousePressEvent(event); // 親クラスの mousePressEvent を呼び出す
    }

private:
    QPlainTextEdit *plainTextEdit;
};

class MainWindow : public QWidget
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr) : QWidget(parent)
    {
        MyCustomWidget *customWidget = new MyCustomWidget(this);
        QVBoxLayout *layout = new QVBoxLayout(this);
        layout->addWidget(customWidget);
        setLayout(layout);

        connect(customWidget, &MyCustomWidget::rightButtonClicked,
                this, &MainWindow::handleRightClick);
    }

private slots:
    void handleRightClick(const QPoint &pos)
    {
        qDebug() << "カスタムウィジェットで右クリックイベントを捕捉しました。位置: " << pos;
        // ここで右クリックの処理を行う
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.setWindowTitle("Custom Widget Signal Example");
    w.resize(400, 200);
    w.show();
    return a.exec();
}

解説

  1. MyCustomWidget クラスを作成し、QPlainTextEdit を内部に含みます。
  2. rightButtonClicked というシグナルを定義します。このシグナルは、右クリックされた位置 (QPoint) を引数として持ちます。
  3. mousePressEvent() をオーバーライドし、右クリックが検出された場合に rightButtonClicked シグナルを発行します。
  4. MainWindow クラスで MyCustomWidget を使用し、rightButtonClicked シグナルを handleRightClick スロットに接続します。
  5. handleRightClick スロットで、右クリックイベントに対する具体的な処理を行います。

マウストラッキング (Mouse Tracking) と mouseMoveEvent() の利用

  • 実装例(簡略化):
  • デメリット
    • 処理が複雑になる可能性
      マウスの動きを常に監視するため、処理が複雑になる可能性があります。
    • パフォーマンスへの影響
      頻繁にイベントが発生するため、処理が重いとパフォーマンスに影響を与える可能性があります。
  • メリット
    • より詳細なマウスの状態の監視
      マウスが移動している間の状態を把握できます。
    • ドラッグ操作などの実装
      ドラッグアンドドロップ操作など、マウスの動きを伴う操作の実装に適しています。
#include <QApplication>
#include <QPlainTextEdit>
#include <QMouseEvent>
#include <QDebug>

class MyPlainTextEditTrack : public QPlainTextEdit
{
public:
    MyPlainTextEditTrack(QWidget *parent = nullptr) : QPlainTextEdit(parent)
    {
        setMouseTracking(true); // マウス追跡を有効にする
    }

protected:
    void mousePressEvent(QMouseEvent *event) override
    {
        if (event->button() == Qt::LeftButton) {
            qDebug() << "左ボタン押下 (トラッキング中)";
            isLeftButtonPressed = true;
            lastPressPos = event->pos();
        }
        QPlainTextEdit::mousePressEvent(event);
    }

    void mouseMoveEvent(QMouseEvent *event) override
    {
        if (isLeftButtonPressed) {
            qDebug() << "左ボタン押下中にマウス移動: " << event->pos();
            // ここでドラッグ操作などの処理を行う
        }
        QPlainTextEdit::mouseMoveEvent(event);
    }

    void mouseReleaseEvent(QMouseEvent *event) override
    {
        if (event->button() == Qt::LeftButton) {
            isLeftButtonPressed = false;
            qDebug() << "左ボタン離されました。";
        }
        QPlainTextEdit::mouseReleaseEvent(event);
    }

private:
    bool isLeftButtonPressed = false;
    QPoint lastPressPos;
};

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

    MyPlainTextEditTrack textEdit;
    textEdit.setPlainText("マウスの移動を追跡します。左ボタンを押しながら移動してみてください。");
    textEdit.setWindowTitle("QPlainTextEdit Mouse Tracking Example");
    textEdit.resize(300, 150);
    textEdit.show();

    return a.exec();
}

解説

  1. コンストラクタで setMouseTracking(true) を呼び出し、マウス追跡を有効にします。
  2. mousePressEvent() で左ボタンが押されたことをフラグで記録し、押下時の位置を保存します。
  3. mouseMoveEvent() で、左ボタンが押されているフラグが立っている場合に、マウスの移動を検知し、対応する処理を行います。
  4. mouseReleaseEvent() で、左ボタンが離されたときにフラグをリセットします。
  • ドラッグ操作や詳細なマウスの状態の監視
    マウスの移動やボタンの状態を詳細に追跡する必要がある場合は、マウストラッキングと mouseMoveEvent() の利用を検討します。
  • 再利用可能なコンポーネントやイベントの分離
    より複雑なロジックや、イベント処理を分離したい場合は、シグナルとスロットを利用したカスタムウィジェットが適しています。
  • イベントの横取りや複数のオブジェクトへの適用
    特定のイベントをより早期に捕捉したり、複数のウィジェットに対して同じ処理を行いたい場合は、イベントフィルタが有効です。
  • 単純なカスタム処理
    QPlainTextEdit の特定のボタンの押下に対する簡単な処理であれば、直接 mousePressEvent() をオーバーライドするのが最もシンプルです。