Model for QListView with checkboxes and text

There is QListView, its filling is done by QStandardItemModel. The list contains elements, each of which has a text and a checkbox. It is necessary that when you click on the text, a checkbox is triggered.

  QStandardItemModel *model = new QStandardItemModel(SIZE_LIST, 1);
  for (int i = 0, sz = SIZE_LIST; i < sz; ++i)
  {
      QStandardItem* item = new QStandardItem;
      item->setData("sometitle", Qt::EditRole);
      item->setData(NUMBER, Qt::UserRole);
      item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
      item->setData(Qt::Unchecked, Qt::CheckStateRole);
      model->setItem(i,0,item);
    }
  }

listView->setModel(model);

When you click on the text, and not on the checkbox, the element should change the state of its checkbox to the opposite. I tried this way: when I click on an item in the list, I call the slot connect(listView,SIGNAL(clicked(QModelIndex)),this,SLOT(slotCheck(QModelIndex)));

Which changes the state of the checkbox to the opposite. But: the signal Clicked is also received when click directly on the checkbox. Thus, when you try to put a check mark in the checkbox, it is reset.

void MyClass::slotCheck(QModelIndex index)
{
  Qt::CheckState state = (Qt::CheckState)
index.model()->data(index,Qt::CheckStateRole).toInt();
  Qt::CheckState newstate = Qt::Checked;
  if (Qt::Checked == state)
  {
    newstate = Qt::Unchecked;
  }
  ui_->descr->model()->setData(index, QVariant(newstate), Qt::CheckStateRole);
}
 2
Author: ixSci, 2016-02-09

3 answers

Use QTreeView instead of QListView as the representation. Leave the text of the first column blank, just set the property: checkable = true. Let the second column contain the text you need.

QStandardItemModel* model = new QStandardItemModel();
fillModel(model);                        // заполняем модель данными
ui->treeview->setModel(model);           // связываем представление с моделью
ui->treeview->setHeaderHidden(true);     // прячем заголовки столбцов (по необходимости)
ui->treeview->resizeColumnToContents(0); // устанавливаем ширину первого столбца равной ширине checkbox'ов
// далее соединяем сигнал со слотом:
connect(ui_->treeview, SIGNAL(clicked(const QModelIndex&)), SLOT(slotClickItem(const QModelIndex&)));

In the slot, check on which column the click occurred: if on the first one, the checkbox itself will change its state, otherwise-we change its state "manually".
Slot implementation:

void slotClickItem(const QModelIndex& index)
{
  QStandardItemModel* model = qobject_cast<QStandardItemModel*>(ui->treeview->model());
  QStandardItem* clickedItem = model->itemFromIndex(index);
  if (clickedItem->column() != 0) {
    QStandardItem* checkedItem = model->item(clickedItem->row(), 0);
    Qt::CheckState currentState = checkedItem->checkState();
    Qt::CheckState nextState = (currentState == Qt::Checked ? Qt::Unchecked : Qt::Checked);
    checkedItem->setCheckState(nextState);
  }
}

Replace the fillModel method with your own, for example, I used this:

void fillModel(QStandardItemModel* model)
{
  QList<QStandardItem*> row;
  const int countRows = 5;
  for (int i = 0; i < countRows; ++i) {
    QStandardItem* item = new QStandardItem();
    item->setCheckable(true);
    row.append(item);

    item = new QStandardItem(QString::number(i+1));
    item->setEditable(false);
    row.append(item);
    model->appendRow(row);
    row.clear();
  }
}
 1
Author: aleks.andr, 2016-02-11 10:02:13

Try using the blockSignals() method for the checkbox, so you will only have one signal from QListView triggered, and the signals from the checkbox will be blocked.

 0
Author: Mira, 2016-02-09 15:41:28

You can inherit QListView and override the protected method:

virtual void QListView::mouseReleaseEvent(QMouseEvent *event);

From event, you can get the coordinates of the mouse click. Next, using the method:

virtual QModelIndex QListView::indexAt(const QPoint &p) const;

... the index of the element that was clicked is obtained. A method:

virtual QRect QListView::visualRect(const QModelIndex &index) const;

... will give the rectangle of this element. Accordingly, if you accept clicks for custom processing only with a certain shift from the left edge (the checkbox is usually located on the left), then you can solve the problem the task.

If "some" shift from the edge of the element does not fix it, then you can refer to the style via QStyleOption and get accurate information about the size of the" square " of the checkbox.

 0
Author: alexis031182, 2016-02-09 15:56:45