【Qt入門】QTableWidgetのcellPressed()シグナル徹底解説:基本から応用まで
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がウィジェットツリーに追加されているか確認する
QMainWindow
やQWidget
などの親ウィジェットに、QTableWidget
が追加されているか確認します。レイアウト(QVBoxLayout
,QHBoxLayout
,QGridLayout
など)を使用している場合は、レイアウトにウィジェットが追加されているか、そのレイアウトが親ウィジェットに設定されているかを確認します。- 例:
layout->addWidget(tableWidget);
- 例:
setCentralWidget(tableWidget);
(QMainWindowの場合)
イベントの遮断 (Event Filtering / Event Handling)
他のウィジェットやイベントフィルタがcellPressed()
イベントを遮断している可能性があります。
エラーの症状
- 他のイベント(例:
cellClicked()
やカスタムのイベントハンドラ)は発火するが、cellPressed()
だけ発火しない。 - 特定のセルや
QTableWidget
全体でcellPressed()
が発火しない。
トラブルシューティング
- カスタムウィジェットがセルに設定されている場合
setCellWidget()
を使ってセルに別のウィジェット(例:QPushButton
、QLineEdit
など)を設定している場合、そのカスタムウィジェットがマウスプレスイベントを吸収してしまうことがあります。この場合、QTableWidget::cellPressed()
ではなく、そのカスタムウィジェットが持つシグナル(例:QPushButton::pressed()
)を使用するか、カスタムウィジェットにイベントフィルタをインストールして手動でイベントを処理する必要があります。
- イベントフィルタの使用を確認する
QTableWidget
やその親ウィジェットにinstallEventFilter()
を使ってイベントフィルタをインストールしている場合、そのフィルタがQEvent::MouseButtonPress
イベントを処理し、event->accept()
またはevent->ignore()
の扱いによってイベントの伝播を停止させていないか確認します。event->ignore()
が呼ばれていれば通常は次のイベントハンドラに渡されますが、複雑なフィルタでは意図しない動作が起こることがあります。
Qt::NoItemFlags の設定 (稀なケース)
非常に稀なケースですが、QTableWidgetItem
にQt::NoItemFlags
が設定されていると、一部のシグナルが発火しないというQtのバグ報告(など)があります。これは古いQtバージョンで特に報告されているようです。
エラーの症状
- セルにアイテムは存在するが、
cellPressed()
が発火しない。
トラブルシューティング
- アイテムのフラグを確認する
QTableWidgetItem::flags()
メソッドでアイテムのフラグを確認します。Qt::ItemIsEnabled
やQt::ItemIsSelectable
などの適切なフラグが設定されていることを確認してください。Qt::NoItemFlags
が設定されている場合は、必要なフラグを追加してみてください。- 例:
item->setFlags(item->flags() | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
シグナルとスロットのデバッグ
上記を確認しても問題が解決しない場合は、デバッグツールを活用します。
トラブルシューティング
- イベントログを確認する
- より高度なデバッグとして、
QApplication
にイベントフィルタをインストールし、すべてのイベントをログに出力することで、QEvent::MouseButtonPress
イベントがQTableWidget
に到達しているかを確認できます。
- より高度なデバッグとして、
- Qt Creator のシグナル/スロットエディタを利用する
- Qt Creatorを使用している場合、UIファイル(
.ui
)のシグナル/スロットエディタで接続が正しく設定されているか視覚的に確認できます。
- Qt Creatorを使用している場合、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) が生成するファイル
解説
- Q_OBJECT マクロ
MyMainWindow
クラスでシグナルとスロットを使用するためには、クラス定義の先頭にQ_OBJECT
マクロが必要です。 - QTableWidget の作成と設定
tableWidget->setRowCount(5);
とtableWidget->setColumnCount(3);
でテーブルのサイズを定義します。tableWidget->setHorizontalHeaderLabels(...)
でヘッダーテキストを設定します。tableWidget->setItem(row, col, new QTableWidgetItem(data));
で各セルにQTableWidgetItem
を設定し、データを表示します。
- connect() 関数
connect(tableWidget, &QTableWidget::cellPressed, this, &MyMainWindow::onCellPressed);
がシグナルとスロットの接続部分です。tableWidget
がシグナルを発するオブジェクト。&QTableWidget::cellPressed
が接続するシグナル(Qt5以降の新しい記法)。this
がスロットを含むオブジェクト。&MyMainWindow::onCellPressed
が呼び出されるスロット。
- onCellPressed スロット
- この関数は
QTableWidget::cellPressed(int row, int column)
シグナルから呼び出され、row
とcolumn
の引数でプレスされたセルの位置を受け取ります。 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"
- メンバー変数の追加
m_pressedRow
とm_pressedColumn
を追加し、現在プレスされているセルの位置を追跡します。これにより、マウスボタンが離れたときにそのセルの色を元に戻すことができます。 - onCellPressed スロット
- 新しいセルがプレスされる前に、以前にハイライトされたセルの色を白に戻します。
- 新しくプレスされたセルの背景色をシアン(
Qt::cyan
)に変更します。 m_pressedRow
とm_pressedColumn
を更新します。
- onCellReleased スロット (簡単な方法)
- ここでは
cellClicked
シグナルをonCellReleased
スロットに接続しています。cellClicked
はマウスボタンが離れた後に発火するため、これで色を元に戻すことができます。しかし、cellPressed
からcellClicked
までにマウスをドラッグして別のセルでリリースした場合、cellClicked
が発火するのはリリースされたセルに対してなので、この方法では厳密な「プレスとリリース」のペアリングはできません。
- ここでは
- イベントフィルタ (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"