もう迷わない!QTableWidgetの列番号取得Q&A:currentColumn()から応用まで

2025-05-27

QtプログラミングにおけるQTableWidget::currentColumn()は、QTableWidgetウィジェット内で現在選択されている(またはフォーカスが当たっている)アイテムの列番号を返す関数です。

もう少し詳しく説明します。

  • currentColumn(): この関数は、その「現在のアイテム」が何番目の列にあるかを返します。列番号は0から始まります。つまり、一番左の列が0、その次が1、といった具合です。
  • 「現在のアイテム (current item)」: QTableWidgetでは、ユーザーがクリックしたり、キーボードで移動したりすることで、特定のセルが「現在のアイテム」として認識されます。この「現在のアイテム」は、ウィジェット内でハイライト表示されることが多いです。
  • QTableWidget: これは、表形式のデータを表示・編集するためのQtのウィジェットです。スプレッドシートのように、行と列にセルが配置されています。

使用例

例えば、QTableWidgetでユーザーがセルをクリックしたときに、そのセルの列番号を取得したい場合などに使用します。

// QTableWidgetのインスタンスがあると仮定します
QTableWidget* tableWidget = new QTableWidget();

// ... 他の初期化処理 ...

// 現在の列番号を取得
int currentColumn = tableWidget->currentColumn();

// 取得した列番号を使って何か処理を行う
qDebug() << "現在の列番号: " << currentColumn;
  • setCurrentCell(int row, int column): 指定した行と列のセルを「現在のアイテム」として設定します。
  • currentItem(): 現在のアイテムであるQTableWidgetItemオブジェクトそのものを返します。
  • currentRow(): 同様に、現在のアイテムの行番号を返します。


QTableWidget::currentColumn()の一般的なエラーとトラブルシューティング

currentColumn()が-1を返す

これは最もよくあるケースです。currentColumn()-1を返す場合、以下の状況が考えられます。

  • 問題: QTableWidget内に選択されているアイテム(current item)が存在しない

    • 原因:
      • QTableWidgetが初期化されたばかりで、まだどのセルも選択されていない。
      • プログラムによって選択が解除された。
      • ユーザーがQTableWidgetからフォーカスを外した。
      • QTableWidgetに表示されているアイテムが一つも存在しない。
    • トラブルシューティング:
      • currentColumn()を呼び出す前に、必ずQTableWidgetに選択されたアイテムがあることを確認してください。currentItem()nullptrでないことを確認するのが良い方法です。
      • もしプログラム的に特定のセルを選択させたい場合は、setCurrentCell(row, column)setCurrentItem(item)を使用してください。
      • ユーザーがQTableWidgetを操作する前にこの値を取得しようとしている場合は、ユーザーが何かを選択するのを待つロジックが必要です(例: シグナルとスロットでitemSelectionChanged()シグナルに接続するなど)。

    コード例(悪い例):

    QTableWidget* table = new QTableWidget(1, 1); // 1行1列のテーブル
    // table->setItem(0, 0, new QTableWidgetItem("データ")); // アイテムを追加するのを忘れた、または選択されていない
    int col = table->currentColumn(); // ここで -1 が返る可能性大
    

    コード例(良い例):

    QTableWidget* table = new QTableWidget(1, 1);
    table->setItem(0, 0, new QTableWidgetItem("データ"));
    table->setCurrentCell(0, 0); // 明示的に選択を設定
    
    if (table->currentItem()) { // currentItem() が nullptr でないことを確認
        int col = table->currentColumn();
        qDebug() << "現在の列: " << col; // 0が出力される
    } else {
        qDebug() << "選択されているアイテムがありません。";
    }
    

想定とは異なる列番号が返される

  • 問題: currentColumn()が返した列番号が、期待しているものと異なる。

    • 原因:
      • 列番号の基点(0始まり)の誤解: Qtのインデックスはほとんどが0から始まります。つまり、一番左の列は0、その右隣は1です。
      • 列の非表示や並べ替え: QTableWidgetの列が非表示になっていたり、ユーザーによって並べ替えられていたりする場合、currentColumn()は表示されている列の視覚的な位置ではなく、内部的な論理的な列番号を返します。これは、非表示の列や並べ替えられた列に対しても一貫したアクセスを提供するためです。
      • 複数の選択モード: QTableWidgetExtendedSelectionMultiSelectionなどの複数選択モードになっている場合、currentColumn()はあくまで**フォーカスがあるアイテム(current item)**の列番号を返します。ユーザーが複数のセルを選択していても、フォーカスがあるのはそのうちの1つだけです。
    • トラブルシューティング:
      • 0始まりの理解: 列番号が0から始まることを常に意識してください。
      • 論理列と視覚列: もし視覚的な列のインデックスが必要な場合は、QHeaderViewの関数(例: visualIndex(int logicalIndex))を使用して変換する必要があります。ただし、通常は論理列番号で十分な場合が多いです。
      • 複数選択の場合: 複数選択されているすべてのアイテムの列番号が必要な場合は、selectedItems()関数を使ってすべての選択されたQTableWidgetItemを取得し、それぞれのアイテムからcolumn()を呼び出す必要があります。

    コード例(論理列と視覚列の比較):

    QTableWidget* table = new QTableWidget(1, 3); // 1行3列
    table->setItem(0, 0, new QTableWidgetItem("A"));
    table->setItem(0, 1, new QTableWidgetItem("B"));
    table->setItem(0, 2, new QTableWidgetItem("C"));
    
    // 列2を非表示にする
    table->setColumnHidden(2, true);
    
    table->setCurrentCell(0, 2); // 内部的に列2を選択
    
    int logicalColumn = table->currentColumn(); // 結果: 2 (論理的な列番号)
    qDebug() << "論理列番号: " << logicalColumn;
    
    // 視覚的な列番号を取得する場合(非表示なので見えない)
    // この場合、currentColumn()で取得したアイテムが非表示の列にあるため、
    // 厳密には視覚的なインデックスは存在しないと考えることもできる
    // 以下のコードは、もし列2が非表示でなかった場合の例
    /*
    if (!table->isColumnHidden(logicalColumn)) {
        int visualColumn = table->horizontalHeader()->visualIndex(logicalColumn);
        qDebug() << "視覚列番号: " << visualColumn;
    }
    */
    

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

  • 問題: currentColumn()を呼び出すタイミングが適切でない。

    • 原因:
      • ユーザーが新しいセルを選択したときに自動的に処理を行いたいのに、適切なシグナルに接続していない、または接続したシグナルがcurrentColumn()の呼び出しに適していない。
    • トラブルシューティング:
      • ユーザーが選択を変更したときに何かをしたい場合は、QTableWidgetの以下のシグナルにスロットを接続することを検討してください。
        • cellClicked(int row, int column): セルがクリックされたとき。
        • cellActivated(int row, int column): セルがアクティブ化されたとき(通常はEnterキーなど)。
        • itemClicked(QTableWidgetItem *item): アイテムがクリックされたとき。
        • currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous): 現在のアイテムが変更されたとき。これが最も汎用的に使えます
        • itemSelectionChanged(): 選択されたアイテムの集合が変更されたとき。複数のセルが選択された場合にも発火します。

    コード例:

    // MyWidget::MyWidget() コンストラクタ内など
    QTableWidget* table = new QTableWidget();
    // ... テーブルの設定とデータ追加 ...
    
    connect(table, &QTableWidget::currentItemChanged, this, [=](QTableWidgetItem *current, QTableWidgetItem *previous) {
        if (current) { // current が nullptr でないことを確認
            qDebug() << "新しい列: " << current->column();
        } else {
            qDebug() << "選択が解除されました。";
        }
    });
    
    // または cellClicked で直接列番号を取得
    connect(table, &QTableWidget::cellClicked, this, [=](int row, int column) {
        qDebug() << "クリックされた列: " << column;
    });
    
  • ドキュメント参照: Qtの公式ドキュメント(QTableWidgetのページ)を定期的に参照し、関数の正確な振る舞いを理解してください。特に、関連するシグナルや他の関数との連携についても確認すると良いでしょう。
  • イベントハンドリング: どのイベント(クリック、キーボード入力など)によってcurrentColumn()を呼び出しているのか、そのイベントが発生した時点でテーブルの状態がどうなっているかを理解してください。
  • デバッグ出力: qDebug()を使って、currentColumn()が実際にどのような値を返しているか、currentItem()nullptrでないかなどを確認してください。

これらの点を理解し、適切にコードを記述することで、QTableWidget::currentColumn()に関する問題を効果的に解決できます。 QTableWidget::currentColumn()は、QTableWidgetの現在の選択アイテムの列番号を返す便利な関数ですが、いくつかの一般的なエラーや予期しない動作が発生することがあります。それらと、そのトラブルシューティングについて説明します。

-1 が返される

エラーの内容
currentColumn()-1を返すことがあります。これは、現在選択されている(またはフォーカスが当たっている)アイテムがないことを意味します。

原因

  • プログラムが自動的にセルを選択する前にcurrentColumn()を呼び出している。
  • 全てのアイテムの選択が解除された後(例: clearSelection()を呼び出した後)。
  • QTableWidgetが初期化されたばかりで、まだ何も選択されていない。

トラブルシューティング

  • シグナルとスロットを適切に使用する
    ユーザーの操作(クリックなど)によって選択が変わる場合は、QTableWidget::currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn)QTableWidget::itemSelectionChanged()シグナルにスロットを接続し、そのスロット内でcurrentColumn()を呼び出すようにします。これにより、選択が変更されたタイミングで正しい値が取得できます。
  • 初期選択を設定する
    プログラムの起動時やデータの読み込み時に、デフォルトで特定のセルを選択するように設定できます。
    tableWidget->setCurrentCell(0, 0); // 0行0列のセルを選択
    
  • アイテムが選択されているか確認する
    QTableWidget::currentItem()nullptrでないことを確認してからcurrentColumn()を呼び出すのが安全です。
    QTableWidgetItem* currentItem = tableWidget->currentItem();
    if (currentItem) {
        int currentColumn = tableWidget->currentColumn();
        // 列番号を使って処理
    } else {
        qDebug() << "現在のアイテムが選択されていません。";
    }
    

予期しない、または古い列番号が返される

エラーの内容
ユーザーが新しいセルを選択したにも関わらず、currentColumn()が以前選択されていたセルの列番号を返すことがあります。これは特に、マウスのドラッグ操作や複数のアイテム選択が絡む場合に報告されています。

原因

  • Qtのバグ (まれに)
    非常にまれですが、特定のQtのバージョンや環境で、このような動作がバグとして報告されることがあります(例: [#QTBUG-102809])。
  • 複雑な選択モード
    QTableWidget::SelectionBehaviorQTableWidget::SelectionModeの設定によっては、ユーザーの操作と内部的な「現在のアイテム」の認識にズレが生じることがあります。
  • イベント処理のタイミングの問題
    UIの更新とイベント処理の間にわずかな遅延がある場合、currentColumn()が古い情報を取得してしまうことがあります。

トラブルシューティング

  • 選択モードの確認
    tableWidget->setSelectionBehavior(QAbstractItemView::SelectItems);tableWidget->setSelectionMode(QAbstractItemView::SingleSelection); のように、選択動作をシンプルに設定することで、予期せぬ挙動を減らせる場合があります。
  • QApplication::processEvents() (非推奨)
    非常に特殊なケースで、UIのイベントキューを強制的に処理させたい場合に使用することがありますが、これは通常推奨されません。UIがフリーズする原因になる可能性があるため、最終手段としてのみ検討してください。
  • currentCellChangedシグナルを使用する
    最も確実な方法は、QTableWidget::currentCellChangedシグナルに接続することです。このシグナルは、現在のセルが変更されたときにcurrentRowcurrentColumn(そしてpreviousRowpreviousColumn)を引数として渡してくれるため、常に正確な情報を取得できます。
    // コンストラクタや初期化関数で接続
    connect(tableWidget, &QTableWidget::currentCellChanged, this, [&](int currentRow, int currentColumn, int previousRow, int previousColumn){
        qDebug() << "新しい現在の列番号: " << currentColumn;
        // ここで currentColumn を使って処理を行う
    });
    

QTableWidgetが存在しない、または無効なオブジェクトで呼び出している

エラーの内容
QTableWidgetオブジェクトがまだ初期化されていない、または既に破棄されている状態でcurrentColumn()を呼び出すと、クラッシュしたり、未定義の動作を引き起こしたりします。

原因

  • オブジェクトの寿命の問題
    QTableWidgetがスコープを外れて破棄された後も、そのポインタを使ってアクセスしようとしている。
  • ポインタの初期化不足
    QTableWidget* tableWidget; と宣言しただけでnew QTableWidget();でインスタンスを作成していない。

トラブルシューティング

  • 適切なメモリ管理
    QTableWidgetをヒープに確保した場合は、必要なくなったときにdeleteするか、親オブジェクトに所有権を任せる(Qtの親子関係による自動削除)など、適切にメモリを管理します。
  • ポインタの有効性チェック
    tableWidgetnullptrでないことを常に確認してからメンバー関数を呼び出します。

QTableWidget::currentColumn()を使用する際の最も一般的な問題は、「いつ呼び出すか」と「現在のアイテムが本当に存在するか」という点に集約されます。

  • currentColumn()を呼び出す前に、currentItem()nullptrでないことを確認する習慣をつけましょう。
  • 常にcurrentCellChangedシグナルを使用するのが最も堅牢で推奨される方法です。


例1: 現在選択されているセルの列番号を取得する (ボタンクリック時)

これは最も基本的な使用例です。ユーザーがボタンをクリックしたときに、現在QTableWidgetで選択されているセルの列番号を表示します。

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

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

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_get_column_button_clicked(); // ボタンクリック時のスロット

private:
    QTableWidget *tableWidget;
    QPushButton *getColumnButton;
};

#endif // MAINWINDOW_H

MainWindow.cpp

#include "MainWindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    // QTableWidgetの作成と初期化
    tableWidget = new QTableWidget(this);
    tableWidget->setRowCount(5); // 5行
    tableWidget->setColumnCount(3); // 3列
    tableWidget->setHorizontalHeaderLabels({"列A", "列B", "列C"}); // ヘッダー設定

    // サンプルデータを追加
    for (int row = 0; row < tableWidget->rowCount(); ++row) {
        for (int col = 0; col < tableWidget->columnCount(); ++col) {
            QTableWidgetItem *item = new QTableWidgetItem(QString("R%1C%2").arg(row).arg(col));
            tableWidget->setItem(row, col, item);
        }
    }

    // ボタンの作成と初期化
    getColumnButton = new QPushButton("現在の列番号を取得", this);
    // ボタンのクリックシグナルとスロットを接続
    connect(getColumnButton, &QPushButton::clicked, this, &MainWindow::on_get_column_button_clicked);

    // レイアウトの設定
    QVBoxLayout *layout = new QVBoxLayout();
    layout->addWidget(tableWidget);
    layout->addWidget(getColumnButton);

    QWidget *centralWidget = new QWidget(this);
    centralWidget->setLayout(layout);
    setCentralWidget(centralWidget);

    setWindowTitle("QTableWidget::currentColumn() 例1");
    resize(400, 300);

    // 初期選択 (任意)
    tableWidget->setCurrentCell(0, 0); // 起動時に(0,0)を選択状態にする
}

MainWindow::~MainWindow()
{
}

void MainWindow::on_get_column_button_clicked()
{
    // 現在選択されているアイテムがあるか確認
    QTableWidgetItem *currentItem = tableWidget->currentItem();
    if (currentItem) {
        int currentColumn = tableWidget->currentColumn();
        qDebug() << "現在の行番号: " << tableWidget->currentRow(); // currentRowも合わせて表示
        qDebug() << "現在の列番号: " << currentColumn;
        QMessageBox::information(this, "現在の列",
                                 QString("選択されているセルの列番号: %1").arg(currentColumn));
    } else {
        QMessageBox::warning(this, "情報", "現在、何も選択されていません。");
        qDebug() << "何も選択されていません。currentColumn()は -1 を返します。";
        qDebug() << "currentColumn()の戻り値: " << tableWidget->currentColumn();
    }
}

main.cpp

#include <QApplication>
#include "MainWindow.h"

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

解説

  1. QTableWidgetを作成し、いくつかの行と列、そしてサンプルデータを追加します。
  2. QPushButtonを作成し、そのclickedシグナルをon_get_column_button_clickedスロットに接続します。
  3. スロット内で、まずtableWidget->currentItem()を使って現在選択されているQTableWidgetItemを取得します。
  4. currentItemnullptrでない(つまり、何か選択されている)ことを確認してから、tableWidget->currentColumn()を呼び出し、現在の列番号を取得して表示します。
  5. もし何も選択されていない場合は、-1が返されることをデバッグ出力で確認できます。

例2: セルの選択が変更されたときに自動的に列番号を更新する

これは、QTableWidgetの選択変更シグナルを利用する、より実践的な例です。ユーザーがセルを選択するたびに、そのセルの列番号が自動的にデバッグ出力やステータスバーなどに表示されます。

MainWindow.h (例1と同じか、一部変更)

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTableWidget>
#include <QDebug>
#include <QLabel> // ステータスバー表示用

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    // セルの選択が変更されたときに呼ばれるスロット
    void on_table_current_cell_changed(int currentRow, int currentColumn, int previousRow, int previousColumn);

private:
    QTableWidget *tableWidget;
    QLabel *statusBarLabel; // ステータスバーに表示するためのラベル
};

#endif // MAINWINDOW_H

MainWindow.cpp

#include "MainWindow.h"
#include <QVBoxLayout>
#include <QWidget>
#include <QStatusBar> // ステータスバー用

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    tableWidget = new QTableWidget(this);
    tableWidget->setRowCount(5);
    tableWidget->setColumnCount(3);
    tableWidget->setHorizontalHeaderLabels({"製品名", "単価", "在庫数"});

    // サンプルデータを追加
    for (int row = 0; row < tableWidget->rowCount(); ++row) {
        tableWidget->setItem(row, 0, new QTableWidgetItem(QString("製品%1").arg(row + 1)));
        tableWidget->setItem(row, 1, new QTableWidgetItem(QString::number((row + 1) * 100)));
        tableWidget->setItem(row, 2, new QTableWidgetItem(QString::number(row * 50)));
    }

    // currentCellChanged シグナルとスロットを接続
    // このシグナルは、現在のセルが変更されたときに自動的にcurrentRowとcurrentColumnを渡してくれる
    connect(tableWidget, &QTableWidget::currentCellChanged,
            this, &MainWindow::on_table_current_cell_changed);

    // ステータスバーの設定
    statusBarLabel = new QLabel("選択セル: なし");
    statusBar()->addWidget(statusBarLabel);

    QVBoxLayout *layout = new QVBoxLayout();
    layout->addWidget(tableWidget);

    QWidget *centralWidget = new QWidget(this);
    centralWidget->setLayout(layout);
    setCentralWidget(centralWidget);

    setWindowTitle("QTableWidget::currentColumn() 例2");
    resize(500, 350);

    // 初期選択 (任意)
    tableWidget->setCurrentCell(0, 0);
}

MainWindow::~MainWindow()
{
}

void MainWindow::on_table_current_cell_changed(int currentRow, int currentColumn,
                                                int previousRow, int previousColumn)
{
    qDebug() << "セルが変更されました:";
    qDebug() << "  新しい行: " << currentRow;
    qDebug() << "  新しい列: " << currentColumn;
    qDebug() << "  古い行: " << previousRow;
    qDebug() << "  古い列: " << previousColumn;

    // 現在の列番号を使用して、特定の処理を行う
    QString columnName;
    if (currentColumn == 0) {
        columnName = "製品名";
    } else if (currentColumn == 1) {
        columnName = "単価";
    } else if (currentColumn == 2) {
        columnName = "在庫数";
    } else {
        columnName = "不明";
    }

    statusBarLabel->setText(QString("選択セル: 行 %1, 列 %2 (%3)").arg(currentRow).arg(currentColumn).arg(columnName));

    // 例: 特定の列が選択されたら何か特別な処理をする
    if (currentColumn == 1) { // 単価の列が選択された場合
        qDebug() << "単価の列が選択されました!";
    }
}

main.cpp (例1と同じ)

#include <QApplication>
#include "MainWindow.h"

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

解説

  1. QTableWidget::currentCellChangedシグナルをon_table_current_cell_changedスロットに接続します。このシグナルは、現在選択されているセルが変更されるたびに自動的に発行されます。
  2. スロットの引数として、新しい行/列番号と、以前の行/列番号が渡されます。これにより、currentColumn()を明示的に呼び出すことなく、常に最新の正確な列番号を取得できます。
  3. 取得した列番号に基づいて、例えばステータスバーのテキストを更新したり、特定の列が選択された場合に特別な処理を実行したりできます。

QTableWidgetで複数選択が可能な場合でも、currentColumn()は「現在のアイテム」に焦点を当てます。QTableWidget::selectedItems()とは異なることに注意してください。

MainWindow.h (例2と同じか、一部変更)

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTableWidget>
#include <QDebug>
#include <QLabel>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_table_current_cell_changed(int currentRow, int currentColumn, int previousRow, int previousColumn);
    // 選択された全てのアイテムを表示するスロット (currentColumn() との比較用)
    void on_table_item_selection_changed();

private:
    QTableWidget *tableWidget;
    QLabel *statusBarLabel;
};

#endif // MAINWINDOW_H

MainWindow.cpp

#include "MainWindow.h"
#include <QVBoxLayout>
#include <QWidget>
#include <QStatusBar>
#include <QList> // QTableWidgetItemのリスト用

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    tableWidget = new QTableWidget(this);
    tableWidget->setRowCount(5);
    tableWidget->setColumnCount(3);
    tableWidget->setHorizontalHeaderLabels({"データ1", "データ2", "データ3"});

    // サンプルデータを追加
    for (int row = 0; row < tableWidget->rowCount(); ++row) {
        for (int col = 0; col < tableWidget->columnCount(); ++col) {
            QTableWidgetItem *item = new QTableWidgetItem(QString("Item R%1C%2").arg(row).arg(col));
            tableWidget->setItem(row, col, item);
        }
    }

    // 複数選択を許可する設定
    tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); // Ctrl/Shiftで複数選択
    tableWidget->setSelectionBehavior(QAbstractItemView::SelectItems); // アイテム単位で選択

    // currentCellChanged シグナルを接続 (currentItem()の列番号に相当)
    connect(tableWidget, &QTableWidget::currentCellChanged,
            this, &MainWindow::on_table_current_cell_changed);

    // itemSelectionChanged シグナルを接続 (選択された全てのアイテムを追跡)
    connect(tableWidget, &QTableWidget::itemSelectionChanged,
            this, &MainWindow::on_table_item_selection_changed);


    statusBarLabel = new QLabel("選択セル: なし (フォーカスなし)");
    statusBar()->addWidget(statusBarLabel);

    QVBoxLayout *layout = new QVBoxLayout();
    layout->addWidget(tableWidget);

    QWidget *centralWidget = new QWidget(this);
    centralWidget->setLayout(layout);
    setCentralWidget(centralWidget);

    setWindowTitle("QTableWidget::currentColumn() 例3 (複数選択)");
    resize(550, 400);

    // 初期選択 (任意)
    tableWidget->setCurrentCell(0, 0);
}

MainWindow::~MainWindow()
{
}

void MainWindow::on_table_current_cell_changed(int currentRow, int currentColumn,
                                                int previousRow, int previousColumn)
{
    // currentColumn() と同じ値がここに渡される
    qDebug() << "== currentCellChanged ==";
    qDebug() << "  フォーカスのあるアイテムの列: " << currentColumn;
    statusBarLabel->setText(QString("フォーカスのあるセル: 行 %1, 列 %2").arg(currentRow).arg(currentColumn));
}

void MainWindow::on_table_item_selection_changed()
{
    // 選択された全てのアイテムの情報を取得
    QList<QTableWidgetItem*> selectedItems = tableWidget->selectedItems();
    qDebug() << "== itemSelectionChanged ==";
    qDebug() << "  選択されたアイテムの数: " << selectedItems.count();

    if (selectedItems.isEmpty()) {
        qDebug() << "  選択されたアイテムはありません。";
    } else {
        qDebug() << "  選択されたアイテムの列:";
        for (QTableWidgetItem* item : selectedItems) {
            qDebug() << "    行: " << item->row() << ", 列: " << item->column() << " (内容: " << item->text() << ")";
        }
    }
}

main.cpp (例1と同じ)

#include <QApplication>
#include "MainWindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc(argv);
    MainWindow w;
    w.show();
    return a.exec();
}
  1. tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);を設定することで、CtrlキーやShiftキーを使った複数選択が可能になります。
  2. on_table_current_cell_changedスロットでは、これまで通りフォーカスのある(カレットがある)単一のアイテムの列番号が表示されます。
  3. 一方、on_table_item_selection_changedスロットでは、tableWidget->selectedItems()を使用して現在選択されている全てのアイテムのリストを取得し、それぞれのアイテムの列番号を表示しています。
  4. この例から、currentColumn()(およびcurrentRow())が常に単一の「現在の」アイテムにのみ関連しており、selectedItems()が返す選択された全てのアイテムとは異なる概念であることが理解できます。


QTableWidget::currentColumn()は、ウィジェット内でカレット(キーボードフォーカスやハイライト表示)がある単一のアイテムの列番号を返します。これに対する代替手段は、主に以下の2つの異なる状況に焦点を当てます。

  1. 特定のセル(アイテム)の列番号を取得したい場合
  2. 選択された複数のセルから列情報を取得したい場合

特定のセル(アイテム)の列番号を取得したい場合

QTableWidget::currentColumn()は、まさに「現在のセル」の列番号を返しますが、もしQTableWidgetItemオブジェクト自体が手元にある場合、そのオブジェクトから列番号を取得できます。

代替方法1: QTableWidgetItem::column()を使う

QTableWidget::currentItem()関数は、QTableWidgetItemポインタを返します。このQTableWidgetItemは、それ自身が所属する行と列の情報を保持しています。

// currentColumn() の代わりに
QTableWidgetItem* currentItem = tableWidget->currentItem();
if (currentItem) {
    int column = currentItem->column(); // QTableWidgetItemから列番号を取得
    qDebug() << "現在のアイテムの列 (QTableWidgetItem::column()): " << column;
} else {
    qDebug() << "何も選択されていません。";
}

利点

  • QTableWidgetItemオブジェクトから直接情報を引き出すため、よりオブジェクト指向的なアプローチと言えます。
  • currentItem()nullptrでないことを確認すれば、安全に列番号を取得できます。

欠点

  • QTableWidget::currentColumn()と機能的にはほぼ同じなので、特に大きな違いはありません。どちらを使うかは好みの問題ですが、currentColumn()の方が直接的で簡潔です。

選択された複数のセルから列情報を取得したい場合

QTableWidget::currentColumn()は単一の「現在のアイテム」に限定されるため、ユーザーが複数選択している場合に、選択された全てのセルの列情報を得るには別の方法が必要です。

代替方法2: QTableWidget::selectedItems()を使う

これは、現在選択されている全てのQTableWidgetItemオブジェクトのリストを返します。このリストをイテレートすることで、選択された全てのセルの列番号を調べることができます。

QList<QTableWidgetItem*> selectedItems = tableWidget->selectedItems();
if (selectedItems.isEmpty()) {
    qDebug() << "選択されたアイテムはありません。";
} else {
    qDebug() << "選択された全てのアイテムの列:";
    QSet<int> selectedColumns; // 重複を避けるためにQSetを使用
    for (QTableWidgetItem* item : selectedItems) {
        selectedColumns.insert(item->column());
        qDebug() << "  行: " << item->row() << ", 列: " << item->column();
    }
    qDebug() << "一意の選択された列: " << selectedColumns.values(); // 全ての異なる列番号
}

利点

  • 例えば、選択された行の中でどの列が選択されているかを判断したい場合に非常に有効です。
  • ユーザーが複数選択を行った場合でも、選択された全てのセルの列情報を網羅的に取得できます。

欠点

  • リストをイテレートする必要があるため、currentColumn()よりは若干コード量が増えます。
  • currentColumn()のように単一の「現在の」列を直接取得するわけではないため、用途が異なります。

代替方法3: QTableWidget::selectionModel()QItemSelectionを使う

より低レベルで柔軟な選択情報へのアクセスが必要な場合、QTableWidget::selectionModel()を介してQItemSelectionModelオブジェクトにアクセスし、QItemSelectionクラスを使用することができます。これは特に複雑な選択範囲の処理(例: 矩形選択の範囲内にある特定の列を判断するなど)で強力です。

QItemSelectionModel* selectionModel = tableWidget->selectionModel();
if (selectionModel->hasSelection()) {
    QModelIndexList selectedIndexes = selectionModel->selectedIndexes();
    qDebug() << "選択されたインデックスの列:";
    QSet<int> selectedColumnsFromIndexes;
    for (const QModelIndex& index : selectedIndexes) {
        selectedColumnsFromIndexes.insert(index.column());
        qDebug() << "  行: " << index.row() << ", 列: " << index.column();
    }
    qDebug() << "一意の選択された列 (QModelIndex): " << selectedColumnsFromIndexes.values();
} else {
    qDebug() << "何も選択されていません。";
}

利点

  • QTableWidgetだけでなく、QListViewQTreeViewなど、他のQtのビュークラスでも共通して使えるモデル/ビューの概念に基づいています。
  • QItemSelectionModelは、単一のセルだけでなく、行全体、列全体、複数のセル範囲など、さまざまな選択モードに対応する柔軟なAPIを提供します。
  • QModelIndexはアイテムの低レベルな情報(モデル内の位置)を提供します。