Eric Johnson
Eric Johnson

Reputation: 826

emit dataChanged(createIndex(1,1),createIndex(1,1)) results in many ::data invocations

I have a QTableView and a corresponding instance of a child of QAbtractTableModel.

I was surprised to see that if my table model instance emits a dataChanged naming a single cell, the Qt framework will then issue a large number of calls to my table model's ::data() member function. The row/column range of those calls appears to cover the entire range of what is on the screen + some extra.

This is more than I expected. I would have thought that a dataChanged() that names a single cell would only result in ::data() calls requesting data for that cell. After all, that's the only cell that my table model said was changed. But the Qt framework appears to be very gregarious and inquires about all the cells.

I clearly have a broken understanding of the intent of the dataChanged() signal.

Is there a way to tell the QTableView to update one cell and one cell only without all the extra chatter sent to my table model?

UPDATE: Including code sample The example here is a header, source, and a chunk of code to create the table. For me, the table displays with 12 columns and 29 rows. After the "issueEmit" invocation at the end, ::data will be invoked 1044 times all because of a dataChanged() signal for a single cell.

// Declaration
#include <QAbstractTableModel>
class SimpleModel : public QAbstractTableModel
{
  Q_OBJECT
private:
  bool _post_emit;
public:
  explicit SimpleModel(QObject *parent=0);
  int rowCount(const QModelIndex &parent = QModelIndex()) const;
  int columnCount(const QModelIndex &parent = QModelIndex()) const;
  QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
  void issueEmit();
};

// Implementation
#include <stdlib.h>
#include <stdio.h>
#include "simplemodel.h"
SimpleModel::SimpleModel(QObject *parent) : QAbstractTableModel(parent), _post_emit(false) { }
int SimpleModel::rowCount(const QModelIndex &parent) const {
  return 100;
}
int SimpleModel::columnCount(const QModelIndex &parent) const {
  return 100;
}
QVariant SimpleModel::data(const QModelIndex &index, int role) const {
  if (role==Qt::DisplayRole) {
    if (_post_emit) {
       static unsigned s_calls=0;
       s_calls++;
       printf("Data calls: %d\n",s_calls);
    }
    return ((rand()%10000)/1000.00);
  }
  return QVariant();
}
void SimpleModel::issueEmit() {
  _post_emit=true;
  emit dataChanged(createIndex(1,1),createIndex(1,1));
}

// Usage
QTableView *table=new QTableView;
table->setMinimumSize(1200,900);
SimpleModel *model=new SimpleModel;
table->setModel(model);
table->show();
model->issueEmit();

Upvotes: 4

Views: 4924

Answers (1)

David D
David D

Reputation: 1591

QVariant QStandardItem::data ( int role = Qt::UserRole + 1 ) const [virtual]

Returns the item's data for the given role, or an invalid QVariant if there is no data for the role.


The argument is really the interesting thing here. Each item in a model holds a number of QVariants, these QVariants maintain different information about the item.

These Variants are all assigned roles. Any time you emit that data has changed the model must redraw the item. To redraw the item it must look at many different pieces of data (small excerpt included below)

Roles describing appearance and meta data (with associated types):
Constant Value Description
Qt::FontRole 6 The font used for items rendered with the default delegate. (QFont)
Qt::TextAlignmentRole 7 The alignment of the text for items rendered with the default delegate. (Qt::AlignmentFlag)
Qt::BackgroundRole 8 The background brush used for items rendered with the default delegate. (QBrush)

Upvotes: 1

Related Questions