【Qt入門】QTableWidgetのcellPressed()シグナル徹底解説:基本から応用まで

2025-05-27

Qtプログラミングにおけるvoid QTableWidget::cellPressed(int row, int column)は、QTableWidgetクラスが持つシグナルの一つです。

以下に詳しく説明します。

  • どんなときに使うか? cellPressed()シグナルは、例えば以下のような状況で役立ちます。

    • ユーザーがセルをプレスしたときに、即座に何らかの視覚的なフィードバックを与えたい場合(例:セルの背景色を一時的に変える)。
    • ドラッグ&ドロップ操作の開始点として、セルがプレスされたことを検出したい場合。
    • cellClicked()よりも細かい粒度でユーザーの操作を検知したい場合。
  • cellPressed(int row, int column)シグナルの意味 このシグナルは、QTableWidget内の特定のセルがマウスで押された瞬間に発せられます。

    • row: マウスで押されたセルの行番号を示します。
    • column: マウスで押されたセルの列番号を示します。

    このシグナルは、マウスボタンが完全に離されたときに発せられるcellClicked()シグナルとは異なります。cellPressed()は、マウスボタンが押された(プレスされた)瞬間に発生し、cellClicked()はマウスボタンが押されてから離されるまでの一連の動作が完了したときに発生します。

  • シグナルとは? Qtにおけるシグナル(Signal)は、オブジェクトが特定のイベントが発生したことを他のオブジェクトに通知するためのメカニズムです。例えば、ボタンがクリックされた、テキストが変更された、といった出来事を知らせるために使われます。シグナルは、そのシグナルを受け取るスロット(Slot)と呼ばれる関数に接続(connect)することで、イベント発生時に特定のアクションを実行させることができます。

  • QTableWidgetとは? QTableWidgetは、Qtフレームワークが提供するウィジェット(GUIコンポーネント)の一つで、表形式のデータを表示・編集するために使われます。Microsoft Excelのようなスプレッドシートに似たグリッド状の表示が特徴です。



QTableWidget::cellPressed() シグナルが期待通りに動作しない場合、いくつかの一般的な原因が考えられます。

シグナルとスロットの接続ミス

最も基本的な問題は、シグナルとスロットの接続が正しく行われていないことです。

エラーの症状

  • アプリケーションがクラッシュする(C++の場合、特に古いQtバージョンや誤った引数型の場合)。
  • セルをクリックしても、対応するスロットが呼び出されない。

トラブルシューティング

  • スロットの宣言を確認する

    • スロットが、クラス定義内で public slots:protected slots:、または private slots: のいずれかのセクションで正しく宣言されているか確認します。
    • シグナルの完全なシグネチャ(引数の型を含む)が正確に記述されているか確認します。
      • 正しい例
        connect(tableWidget, &QTableWidget::cellPressed, this, &MyClass::onCellPressed); (Qt5以降の新しい記法)
      • 正しい例(古い記法)
        connect(tableWidget, SIGNAL(cellPressed(int, int)), this, SLOT(onCellPressed(int, int)));
      • よくある間違い(古い記法)
        SIGNAL(cellPressed(x, y)) のように変数名を使うのではなく、SIGNAL(cellPressed(int, int)) のように型名を使用する必要があります。
    • スロットのシグネチャも同様に正確であるか確認します。
    • this ポインタが、シグナルを発するオブジェクトとスロットを含むオブジェクトを正しく指しているか確認します。

QTableWidget の初期化と表示の問題

QTableWidget自体が正しく初期化・表示されていない場合、イベントが発生しません。

エラーの症状

  • セルが見当たらないため、プレスする対象がない。
  • QTableWidgetがウィンドウに表示されない、または空白のまま。

トラブルシューティング

  • アイテムが設定されているか確認する

    • セルにQTableWidgetItemが設定されていない場合でもcellPressed()は発生しますが、視覚的にセルが存在しないように見えることがあります。意図した通りにアイテムが表示されているか確認します。
    • 例: tableWidget->setItem(row, column, new QTableWidgetItem("テキスト"));
  • 行と列が設定されているか確認する

    • setRowCount()setColumnCount() で、テーブルの行と列の数が適切に設定されているか確認します。
    • 例: tableWidget->setRowCount(5); tableWidget->setColumnCount(3);
  • QTableWidgetがウィジェットツリーに追加されているか確認する

    • QMainWindowQWidget などの親ウィジェットに、QTableWidgetが追加されているか確認します。レイアウト(QVBoxLayout, QHBoxLayout, QGridLayoutなど)を使用している場合は、レイアウトにウィジェットが追加されているか、そのレイアウトが親ウィジェットに設定されているかを確認します。
    • 例: layout->addWidget(tableWidget);
    • 例: setCentralWidget(tableWidget); (QMainWindowの場合)

イベントの遮断 (Event Filtering / Event Handling)

他のウィジェットやイベントフィルタがcellPressed()イベントを遮断している可能性があります。

エラーの症状

  • 他のイベント(例:cellClicked()やカスタムのイベントハンドラ)は発火するが、cellPressed()だけ発火しない。
  • 特定のセルやQTableWidget全体でcellPressed()が発火しない。

トラブルシューティング

  • カスタムウィジェットがセルに設定されている場合
    • setCellWidget() を使ってセルに別のウィジェット(例:QPushButtonQLineEditなど)を設定している場合、そのカスタムウィジェットがマウスプレスイベントを吸収してしまうことがあります。この場合、QTableWidget::cellPressed()ではなく、そのカスタムウィジェットが持つシグナル(例:QPushButton::pressed())を使用するか、カスタムウィジェットにイベントフィルタをインストールして手動でイベントを処理する必要があります。
  • イベントフィルタの使用を確認する
    • QTableWidgetやその親ウィジェットにinstallEventFilter()を使ってイベントフィルタをインストールしている場合、そのフィルタがQEvent::MouseButtonPressイベントを処理し、event->accept()またはevent->ignore()の扱いによってイベントの伝播を停止させていないか確認します。event->ignore()が呼ばれていれば通常は次のイベントハンドラに渡されますが、複雑なフィルタでは意図しない動作が起こることがあります。

Qt::NoItemFlags の設定 (稀なケース)

非常に稀なケースですが、QTableWidgetItemQt::NoItemFlagsが設定されていると、一部のシグナルが発火しないというQtのバグ報告(など)があります。これは古いQtバージョンで特に報告されているようです。

エラーの症状

  • セルにアイテムは存在するが、cellPressed()が発火しない。

トラブルシューティング

  • アイテムのフラグを確認する
    • QTableWidgetItem::flags() メソッドでアイテムのフラグを確認します。Qt::ItemIsEnabledQt::ItemIsSelectable などの適切なフラグが設定されていることを確認してください。Qt::NoItemFlags が設定されている場合は、必要なフラグを追加してみてください。
    • 例: item->setFlags(item->flags() | Qt::ItemIsEnabled | Qt::ItemIsSelectable);

シグナルとスロットのデバッグ

上記を確認しても問題が解決しない場合は、デバッグツールを活用します。

トラブルシューティング

  • イベントログを確認する
    • より高度なデバッグとして、QApplicationにイベントフィルタをインストールし、すべてのイベントをログに出力することで、QEvent::MouseButtonPressイベントがQTableWidgetに到達しているかを確認できます。
  • Qt Creator のシグナル/スロットエディタを利用する
    • Qt Creatorを使用している場合、UIファイル(.ui)のシグナル/スロットエディタで接続が正しく設定されているか視覚的に確認できます。
  • デバッグ出力(qDebug())を使う
    • cellPressed()に接続されたスロットの最初にqDebug()でメッセージを出力し、スロットが呼び出されているかを確認します。
    • 例:
      void MyClass::onCellPressed(int row, int column) {
          qDebug() << "Cell pressed at row:" << row << ", column:" << column;
          // 他の処理
      }
      


例1: セルがプレスされたときにメッセージを出力するシンプルな例

この例では、QTableWidgetを作成し、いくつかのデータを設定します。セルがプレスされるたびに、そのセルの行と列のインデックスをデバッグ出力に表示します。

main.cpp

#include <QApplication>
#include <QMainWindow>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug> // デバッグ出力用

class MyMainWindow : public QMainWindow
{
    Q_OBJECT // シグナルとスロットを使用するために必要

public:
    MyMainWindow(QWidget *parent = nullptr)
        : QMainWindow(parent)
    {
        setWindowTitle("QTableWidget cellPressed Example");
        resize(600, 400);

        QTableWidget *tableWidget = new QTableWidget(this);
        tableWidget->setRowCount(5); // 5行
        tableWidget->setColumnCount(3); // 3列

        // ヘッダーを設定
        QStringList horizontalHeader;
        horizontalHeader << "名前" << "年齢" << "都市";
        tableWidget->setHorizontalHeaderLabels(horizontalHeader);

        // ダミーデータを設定
        for (int row = 0; row < 5; ++row) {
            for (int col = 0; col < 3; ++col) {
                QString data = QString("セル(%1, %2)").arg(row).arg(col);
                tableWidget->setItem(row, col, new QTableWidgetItem(data));
            }
        }

        // シグナルとスロットを接続
        // QTableWidgetのcellPressedシグナルを、このクラスのonCellPressedスロットに接続
        connect(tableWidget, &QTableWidget::cellPressed,
                this, &MyMainWindow::onCellPressed);

        // レイアウトにテーブルウィジェットを追加
        QWidget *centralWidget = new QWidget(this);
        QVBoxLayout *layout = new QVBoxLayout(centralWidget);
        layout->addWidget(tableWidget);
        setCentralWidget(centralWidget);
    }

private slots:
    // セルがプレスされたときに呼び出されるスロット
    void onCellPressed(int row, int column)
    {
        qDebug() << "セルがプレスされました: 行 =" << row << ", 列 =" << column;
        // 例: プレスされたセルのテキストを取得して表示
        QTableWidgetItem *item = tableWidget()->item(row, column);
        if (item) {
            qDebug() << "テキスト:" << item->text();
        }
    }

    // テーブルウィジェットへのポインタを返すヘルパー関数 (便利のため)
    QTableWidget* tableWidget() const {
        return findChild<QTableWidget*>(); // 子ウィジェットからQTableWidgetを探す
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MyMainWindow mainWindow;
    mainWindow.show();
    return app.exec();
}

#include "main.moc" // MOC (Meta-Object Compiler) が生成するファイル

解説

  1. Q_OBJECT マクロ
    MyMainWindow クラスでシグナルとスロットを使用するためには、クラス定義の先頭にQ_OBJECTマクロが必要です。
  2. QTableWidget の作成と設定
    • tableWidget->setRowCount(5);tableWidget->setColumnCount(3); でテーブルのサイズを定義します。
    • tableWidget->setHorizontalHeaderLabels(...) でヘッダーテキストを設定します。
    • tableWidget->setItem(row, col, new QTableWidgetItem(data)); で各セルにQTableWidgetItemを設定し、データを表示します。
  3. connect() 関数
    • connect(tableWidget, &QTableWidget::cellPressed, this, &MyMainWindow::onCellPressed); がシグナルとスロットの接続部分です。
    • tableWidget がシグナルを発するオブジェクト。
    • &QTableWidget::cellPressed が接続するシグナル(Qt5以降の新しい記法)。
    • this がスロットを含むオブジェクト。
    • &MyMainWindow::onCellPressed が呼び出されるスロット。
  4. onCellPressed スロット
    • この関数はQTableWidget::cellPressed(int row, int column)シグナルから呼び出され、rowcolumnの引数でプレスされたセルの位置を受け取ります。
    • qDebug() を使って、デバッグコンソールにメッセージを出力します。

この例では、cellPressed()シグナルを使って、セルがプレスされた瞬間にそのセルの背景色を変更し、マウスボタンが離されたら元に戻す(または別の色にする)といった視覚的なフィードバックを実装します。

main.cpp

#include <QApplication>
#include <QMainWindow>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug>
#include <QBrush> // 色設定用
#include <QMouseEvent> // イベント処理用

class MyMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MyMainWindow(QWidget *parent = nullptr)
        : QMainWindow(parent),
          m_pressedRow(-1), // プレスされたセルの行を保持
          m_pressedColumn(-1) // プレスされたセルの列を保持
    {
        setWindowTitle("QTableWidget cellPressed Color Change");
        resize(600, 400);

        QTableWidget *tableWidget = new QTableWidget(this);
        tableWidget->setRowCount(5);
        tableWidget->setColumnCount(3);

        // ヘッダーを設定
        QStringList horizontalHeader;
        horizontalHeader << "アイテム" << "数量" << "価格";
        tableWidget->setHorizontalHeaderLabels(horizontalHeader);

        // ダミーデータを設定
        for (int row = 0; row < 5; ++row) {
            for (int col = 0; col < 3; ++col) {
                QString data = QString("データ %1,%2").arg(row).arg(col);
                QTableWidgetItem *item = new QTableWidgetItem(data);
                item->setTextAlignment(Qt::AlignCenter); // テキストを中央寄せ
                tableWidget->setItem(row, col, item);
            }
        }

        // シグナルとスロットを接続
        connect(tableWidget, &QTableWidget::cellPressed,
                this, &MyMainWindow::onCellPressed);
        // マウスボタンが離されたときにセルを元に戻すために、cellReleasedやviewportEventを考慮することもできますが、
        // ここでは簡単な例としてcellClickedでも色を戻すようにします。
        // より正確には、QTableWidgetのサブクラス化でmouseReleaseEventをオーバーライドするのが良いでしょう。
        connect(tableWidget, &QTableWidget::cellClicked, // 例としてcellClickedを使用
                this, &MyMainWindow::onCellReleased);

        // QTableWidgetにイベントフィルタをインストールして、マウスリリースイベントを捕捉することもできます
        tableWidget->viewport()->installEventFilter(this);


        QWidget *centralWidget = new QWidget(this);
        QVBoxLayout *layout = new QVBoxLayout(centralWidget);
        layout->addWidget(tableWidget);
        setCentralWidget(centralWidget);
    }

private slots:
    void onCellPressed(int row, int column)
    {
        qDebug() << "セルがプレスされました: 行 =" << row << ", 列 =" << column;

        // 以前にプレスされたセルがあれば、色を元に戻す
        if (m_pressedRow != -1 && m_pressedColumn != -1) {
            QTableWidgetItem *prevItem = tableWidget()->item(m_pressedRow, m_pressedColumn);
            if (prevItem) {
                prevItem->setBackground(QBrush(Qt::white)); // デフォルトの色に戻す
            }
        }

        // 新しくプレスされたセルの背景色を変更
        QTableWidgetItem *currentItem = tableWidget()->item(row, column);
        if (currentItem) {
            currentItem->setBackground(QBrush(Qt::cyan)); // シアン色に変更
        }

        // プレスされたセルの情報を保存
        m_pressedRow = row;
        m_pressedColumn = column;
    }

    void onCellReleased(int row, int column) {
        // cellClickedはmouseReleaseEvent後に発火するので、ここでは色を元に戻す
        qDebug() << "セルがクリックされました (リリースされた): 行 =" << row << ", 列 =" << column;
        if (m_pressedRow != -1 && m_pressedColumn != -1) {
            QTableWidgetItem *prevItem = tableWidget()->item(m_pressedRow, m_pressedColumn);
            if (prevItem) {
                prevItem->setBackground(QBrush(Qt::white)); // デフォルトの色に戻す
            }
            m_pressedRow = -1; // リセット
            m_pressedColumn = -1; // リセット
        }
    }

protected:
    // イベントフィルタの実装 (より正確なマウスリリースイベントの捕捉のため)
    bool eventFilter(QObject *obj, QEvent *event) override {
        if (obj == tableWidget()->viewport() && event->type() == QEvent::MouseButtonRelease) {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
            if (mouseEvent->button() == Qt::LeftButton) {
                // マウス位置からセルを取得
                QTableWidgetItem *item = tableWidget()->itemAt(mouseEvent->pos());
                if (item) {
                    int row = item->row();
                    int column = item->column();
                    qDebug() << "Viewport Mouse Released at cell: (" << row << "," << column << ")";
                    // ここで色を元に戻す処理を行う
                    if (m_pressedRow != -1 && m_pressedColumn != -1) {
                        QTableWidgetItem *prevItem = tableWidget()->item(m_pressedRow, m_pressedColumn);
                        if (prevItem) {
                            prevItem->setBackground(QBrush(Qt::white));
                        }
                        m_pressedRow = -1;
                        m_pressedColumn = -1;
                    }
                }
            }
        }
        return QMainWindow::eventFilter(obj, event);
    }

private:
    int m_pressedRow;
    int m_pressedColumn;

    QTableWidget* tableWidget() const {
        return findChild<QTableWidget*>();
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MyMainWindow mainWindow;
    mainWindow.show();
    return app.exec();
}

#include "main.moc"
  1. メンバー変数の追加
    m_pressedRowm_pressedColumn を追加し、現在プレスされているセルの位置を追跡します。これにより、マウスボタンが離れたときにそのセルの色を元に戻すことができます。
  2. onCellPressed スロット
    • 新しいセルがプレスされる前に、以前にハイライトされたセルの色を白に戻します。
    • 新しくプレスされたセルの背景色をシアン(Qt::cyan)に変更します。
    • m_pressedRowm_pressedColumn を更新します。
  3. onCellReleased スロット (簡単な方法)
    • ここではcellClickedシグナルをonCellReleasedスロットに接続しています。cellClickedはマウスボタンが離れた後に発火するため、これで色を元に戻すことができます。しかし、cellPressedからcellClickedまでにマウスをドラッグして別のセルでリリースした場合、cellClickedが発火するのはリリースされたセルに対してなので、この方法では厳密な「プレスとリリース」のペアリングはできません。
  4. イベントフィルタ (eventFilter および installEventFilter) (より正確な方法)
    • QTableWidgetのビューポート(実際にアイテムが描画される部分)にイベントフィルタをインストールしています。
    • eventFilterメソッドをオーバーライドし、QEvent::MouseButtonReleaseイベントを捕捉します。
    • イベントの発生源がテーブルウィジェットのビューポートであり、マウスボタンが左クリックであった場合、tableWidget()->itemAt(mouseEvent->pos())を使ってマウスが離された位置にあるセルを取得します。
    • その後、保存しておいたm_pressedRow/m_pressedColumnのセルを元の色に戻します。この方法は、ユーザーがセル上でマウスをプレスし、そのセルを離したときに色を元に戻すという挙動をより正確に実現します。


以下に、cellPressed() の代替方法をいくつか説明します。

QTableWidget をサブクラス化し、mousePressEvent() をオーバーライドする

これは、QTableWidget のマウスイベント処理を最も細かく制御できる強力な方法です。

利点

  • イベントの伝播を制御(event->accept()event->ignore())できます。
  • QMouseEvent オブジェクトから、マウスの位置、押されたボタン、修飾キー(Shift, Ctrlなど)といった詳細な情報を取得できます。
  • QTableWidget が受け取るすべてのマウスプレスイベントを直接処理できます。

欠点

  • QTableWidget::cellPressed() シグナルが提供する (row, column) 情報は、自分でマウスの位置から計算する必要があります。
  • QTableWidget を継承する新しいクラスを作成する必要があります。

コード例

#include <QApplication>
#include <QMainWindow>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug>
#include <QMouseEvent> // QMouseEvent を使用

// QTableWidget を継承したカスタムクラス
class MyTableWidget : public QTableWidget
{
    Q_OBJECT
public:
    MyTableWidget(QWidget *parent = nullptr)
        : QTableWidget(parent)
    {
    }

protected:
    // mousePressEvent をオーバーライド
    void mousePressEvent(QMouseEvent *event) override
    {
        // 親クラスの処理を呼び出す (通常は必要)
        QTableWidget::mousePressEvent(event);

        // 左クリックが押された場合のみ処理
        if (event->button() == Qt::LeftButton) {
            // マウスの位置からアイテムのインデックスを取得
            QTableWidgetItem *item = itemAt(event->pos());
            if (item) {
                int row = item->row();
                int column = item->column();
                qDebug() << "MyTableWidget::mousePressEvent - セルがプレスされました: 行 =" << row << ", 列 =" << column;
                qDebug() << "押されたボタン:" << event->button();
                qDebug() << "修飾キー:" << event->modifiers();

                // ここでカスタムの処理を行う
                // 例: セルの背景色を変更
                item->setBackground(QBrush(Qt::yellow));
            } else {
                // セル以外の場所がクリックされた場合
                qDebug() << "テーブルのセル以外の場所がプレスされました。";
            }
        }
    }
};

class MyMainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MyMainWindow(QWidget *parent = nullptr)
        : QMainWindow(parent)
    {
        setWindowTitle("Custom QTableWidget Mouse Press Event");
        resize(600, 400);

        MyTableWidget *tableWidget = new MyTableWidget(this);
        tableWidget->setRowCount(5);
        tableWidget->setColumnCount(3);

        for (int row = 0; row < 5; ++row) {
            for (int col = 0; col < 3; ++col) {
                tableWidget->setItem(row, col, new QTableWidgetItem(QString("データ %1,%2").arg(row).arg(col)));
            }
        }

        QWidget *centralWidget = new QWidget(this);
        QVBoxLayout *layout = new QVBoxLayout(centralWidget);
        layout->addWidget(tableWidget);
        setCentralWidget(centralWidget);
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MyMainWindow mainWindow;
    mainWindow.show();
    return app.exec();
}

#include "main.moc"

イベントフィルタを使用する

QTableWidget オブジェクト自体にイベントフィルタをインストールすることで、そのオブジェクトが受け取るすべてのイベントを監視・処理できます。これは、QTableWidget をサブクラス化せずに特定のイベントを捕捉したい場合に便利です。

利点

  • 複数のウィジェットに対して同じイベントフィルタを適用できます。
  • 既存の QTableWidget インスタンスに対してイベント処理を追加できます。

欠点

  • cellPressed() シグナルと同様に、イベントフィルタ内からマウスの位置(QMouseEvent::pos())を使って、itemAt() でセルの行と列を自分で取得する必要があります。
  • イベントフィルタリングロジックが、イベントフィルタをインストールしたクラスに散らばる可能性があります。

コード例

#include <QApplication>
#include <QMainWindow>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug>
#include <QMouseEvent>
#include <QEvent> // QEvent を使用

class MyMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MyMainWindow(QWidget *parent = nullptr)
        : QMainWindow(parent)
    {
        setWindowTitle("QTableWidget Event Filter Example");
        resize(600, 400);

        QTableWidget *tableWidget = new QTableWidget(this);
        tableWidget->setRowCount(5);
        tableWidget->setColumnCount(3);

        for (int row = 0; row < 5; ++row) {
            for (int col = 0; col < 3; ++col) {
                tableWidget->setItem(row, col, new QTableWidgetItem(QString("データ %1,%2").arg(row).arg(col)));
            }
        }

        // QTableWidget にイベントフィルタをインストール
        tableWidget->viewport()->installEventFilter(this); // ビューポートにインストールするのが一般的

        m_tableWidget = tableWidget; // メンバー変数として保持

        QWidget *centralWidget = new QWidget(this);
        QVBoxLayout *layout = new QVBoxLayout(centralWidget);
        layout->addWidget(tableWidget);
        setCentralWidget(centralWidget);
    }

protected:
    // イベントフィルタのオーバーライド
    bool eventFilter(QObject *obj, QEvent *event) override
    {
        // QTableWidgetのビューポートからのイベントか確認
        if (obj == m_tableWidget->viewport() && event->type() == QEvent::MouseButtonPress) {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
            if (mouseEvent->button() == Qt::LeftButton) {
                QTableWidgetItem *item = m_tableWidget->itemAt(mouseEvent->pos());
                if (item) {
                    int row = item->row();
                    int column = item->column();
                    qDebug() << "Event Filter - セルがプレスされました: 行 =" << row << ", 列 =" << column;
                    qDebug() << "押されたボタン:" << mouseEvent->button();
                    // 必要であれば、イベントの伝播をここで停止させることも可能
                    // return true; // イベントを処理済みとして、他のハンドラへ渡さない
                }
            }
        }
        // 他のイベントは通常通り処理を続行させる
        return QMainWindow::eventFilter(obj, event);
    }

private:
    QTableWidget *m_tableWidget;
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MyMainWindow mainWindow;
    mainWindow.show();
    return app.exec();
}

#include "main.moc"

QTableWidgetItem をサブクラス化し、カスタムウィジェットをセルに設定する (setCellWidget())

もし、セル自体に特殊なインタラクションを持たせたい(例:ボタン、チェックボックスなど)のであれば、QTableWidgetItem ではなく、QWidget を継承したカスタムウィジェットを作成し、それを QTableWidget::setCellWidget() でセルに設定する方法があります。

利点

  • セルの見た目と動作を完全にカスタマイズできます。
  • 各セルが独立したウィジェットとなり、そのウィジェット独自のイベントハンドリングやシグナル/スロットを持つことができます。

欠点

  • 大量のセルにカスタムウィジェットを設定すると、パフォーマンスに影響が出る可能性があります(特に多数の行がある場合)。
  • QTableWidgetItem の標準機能(テキスト、アイコンなど)は利用できず、カスタムウィジェット内で実装する必要があります。
#include <QApplication>
#include <QMainWindow>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QVBoxLayout>
#include <QWidget>
#include <QDebug>
#include <QPushButton> // セルにボタンを配置する例

// カスタムセルウィジェット
class MyCellWidget : public QWidget
{
    Q_OBJECT
public:
    // コンストラクタでセルの行と列を受け取る
    MyCellWidget(int row, int column, QWidget *parent = nullptr)
        : QWidget(parent), m_row(row), m_column(column)
    {
        QVBoxLayout *layout = new QVBoxLayout(this);
        layout->setContentsMargins(0, 0, 0, 0); // マージンをなくす

        QPushButton *button = new QPushButton(QString("セル %1,%2").arg(row).arg(column), this);
        layout->addWidget(button);

        // ボタンのpressedシグナルを、MyCellWidgetのpressedシグナルに接続
        connect(button, &QPushButton::pressed, this, &MyCellWidget::cellButton_pressed);
    }

signals:
    // このカスタムウィジェットが発するシグナル
    void cellButton_pressed(int row, int column);

private slots:
    void cellButton_pressed()
    {
        // ボタンが押されたら、このカスタムウィジェットのシグナルを発する
        emit cellButton_pressed(m_row, m_column);
    }

private:
    int m_row;
    int m_column;
};


class MyMainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MyMainWindow(QWidget *parent = nullptr)
        : QMainWindow(parent)
    {
        setWindowTitle("QTableWidget Custom Cell Widget");
        resize(600, 400);

        QTableWidget *tableWidget = new QTableWidget(this);
        tableWidget->setRowCount(5);
        tableWidget->setColumnCount(3);

        for (int row = 0; row < 5; ++row) {
            for (int col = 0; col < 3; ++col) {
                MyCellWidget *cellWidget = new MyCellWidget(row, col);
                // カスタムウィジェットのシグナルをメインウィンドウのスロットに接続
                connect(cellWidget, &MyCellWidget::cellButton_pressed,
                        this, &MyMainWindow::onCustomCellButtonPressed);
                tableWidget->setCellWidget(row, col, cellWidget);
            }
        }

        QWidget *centralWidget = new QWidget(this);
        QVBoxLayout *layout = new QVBoxLayout(centralWidget);
        layout->addWidget(tableWidget);
        setCentralWidget(centralWidget);
    }

private slots:
    // カスタムセルウィジェットのボタンが押されたときに呼び出されるスロット
    void onCustomCellButtonPressed(int row, int column)
    {
        qDebug() << "カスタムセルウィジェットのボタンがプレスされました: 行 =" << row << ", 列 =" << column;
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MyMainWindow mainWindow;
    mainWindow.show();
    return app.exec();
}

#include "main.moc"