クリックでアクションを実行!Qt WidgetsのQAbstractItemView::clicked()シグナルを使いこなして開発を効率化


QAbstractItemView::clicked()シグナルは、Qt Widgetsライブラリの様々なアイテムビューウィジェット(QListWidget、QTreeWidget、QTableViewなど)において、マウスの左ボタンがクリックされたときに発生します。このシグナルは、クリックされたアイテムに関する情報を提供し、そのアイテムに基づいてアクションを実行することができます。

シグナルの引数

QAbstractItemView::clicked()シグナルは、以下の引数を渡します。

  • const QModelIndex &index: クリックされたアイテムに対応するモデルインデックス

シグナルの接続

QAbstractItemView::clicked()シグナルを接続するには、connect()関数を使用します。以下の例は、QListWidgetのclicked()シグナルをスロットに接続する方法を示しています。

QListWidget *listView;

void connectSignals() {
  connect(listView, &QListWidget::clicked, this, &MyClass::onItemClicked);
}

void MyClass::onItemClicked(const QModelIndex &index) {
  // クリックされたアイテムに関する処理を実行
  QModelIndex parent = index.parent();
  QString text = index.data().toString();
  qDebug() << "Item clicked:" << text;
}

シグナルの利用例

QAbstractItemView::clicked()シグナルは、様々な目的に利用することができます。以下に、いくつかの例を紹介します。

  • アイテムの削除: クリックされたアイテムを削除することができます。
  • アイテムの編集: クリックされたアイテムを編集モードにし、ユーザーが入力できるようにすることができます。
  • シグナルは、アイテムが編集モードの場合は発生しません。
  • シグナルは、アイテムビューウィジェットがフォーカスを持っている場合にのみ発生します。
  • シグナルは、有効なモデルインデックスがクリックされた場合にのみ発生します。


#include <QApplication>
#include <QMainWindow>
#include <QListWidget>

class MyWindow : public QMainWindow {
public:
  MyWindow() {
    // ウィジェットを作成
    QListWidget *listView = new QListWidget;
    listView->addItem("Item 1");
    listView->addItem("Item 2");
    listView->addItem("Item 3");

    // シグナルを接続
    connect(listView, &QListWidget::clicked, this, &MyWindow::onItemClicked);

    // ウィジェットをレイアウト
    setCentralWidget(listView);
  }

signals:
  void itemClicked(const QModelIndex &index);

private slots:
  void onItemClicked(const QModelIndex &index) {
    // クリックされたアイテムのテキストをログに出力
    QString text = index.data().toString();
    qDebug() << "Item clicked:" << text;
  }
};

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


QAbstractItemModel::dataChanged()シグナル

QAbstractItemModel::dataChanged()シグナルは、モデル内のデータが変更されたときに発生します。このシグナルは、アイテムビューウィジェットだけでなく、モデルデータに直接アクセスする他の部分からも利用することができます。

connect(model, &QAbstractItemModel::dataChanged, this, &MyClass::onDataChanged);

void MyClass::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
                             const QVector<int> &roles) {
  // データが変更されたアイテムに関する処理を実行
  QModelIndex index = topLeft;
  while (index.isValid()) {
    if (roles.contains(Qt::DisplayRole)) {
      QString text = index.data().toString();
      qDebug() << "Item text changed:" << text;
    }
    index = index.parent();
  }
}

キーボードイベント

キーボードイベントは、アイテムビューウィジェットでキーが押されたときに発生します。このイベントは、アイテムがクリックされたかどうかだけでなく、どのキーが押されたかなどの詳細な情報を取得することができます。

listView->installEventFilter(this);

bool MyClass::eventFilter(QObject *obj, QEvent *event) {
  if (event->type() == QEvent::KeyPress) {
    QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
    if (keyEvent->key() == Qt::Key_Enter) {
      QModelIndex index = listView->currentIndex();
      if (index.isValid()) {
        QString text = index.data().toString();
        qDebug() << "Item entered:" << text;
      }
    }
  }
  return QObject::eventFilter(obj, event);
}

カスタムシグナル

カスタムシグナルは、アプリケーション固有のイベントを通知するために使用することができます。このシグナルは、QAbstractItemView::clicked()シグナルよりも柔軟性があり、より詳細な情報を提供することができます。

class MyItem : public QModelIndex {
public:
  MyItem(const QModelIndex &parent, int row, int column, const QVariant &data)
      : QModelIndex(parent, row, column, data) {}

  QString customText() const { return data(Qt::UserRole).toString(); }
};

class MyModel : public QAbstractItemModel {
public:
  MyModel(const QVector<MyItem> &items) : items_(items) {}

  int rowCount(const QModelIndex &parent) const override {
    if (parent.isValid()) {
      return 0;
    }
    return items_.size();
  }

  QModelIndex index(int row, int column, const QModelIndex &parent) const override {
    if (parent.isValid() || row < 0 || row >= items_.size() || column != 0) {
      return QModelIndex();
    }
    return MyItem(parent, row, column, items_[row].data());
  }

  QVariant data(const QModelIndex &index, int role) const override {
    if (!index.isValid()) {
      return QVariant();
    }
    if (role == Qt::DisplayRole) {
      return items_[index.row()].customText();
    }
    return QVariant();
  }

signals:
  void itemClicked(const MyItem &item);
};

class MyWindow : public QMainWindow {
public:
  MyWindow() {
    // ウィジェットを作成
    listView = new QListView;
    model = new MyModel({
        MyItem(QModelIndex(), 0, 0, "Item 1"),
        MyItem(QModelIndex(), 1, 0, "Item 2"),
        MyItem(QModelIndex(), 2, 0, "Item 3"),
    });
    listView->setModel(model);

    // シグナルを接続
    connect(model, &MyModel::itemClicked, this, &MyWindow::onItemClicked);

    // ウィジェットをレイアウト
    setCentralWidget(listView);
  }

signals:
  void itemClicked