Reputation: 45
my Problem is, when using
QStandarditemmodel::setData(const QModelIndex &index, const QVariant &value, int role)
it seems that the role is never emitted.
Example:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QStandardItemModel *model = new QStandardItemModel();
QList<QStandardItem*> itemList;
itemList.append(new QStandardItem());
model->appendRow(itemList);
connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), this, SLOT(myslot_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
model->item(0,0)->setData("supercool value", Qt::DisplayRole); // // should emit 1 role, but 0 are arriving
model->item(0,0)->setData("another supercool value", Qt::UserRole); // // should emit 1 role, but 0 are arriving
QVector<int> roles;
roles.append(Qt::DisplayRole);
roles.append(Qt::UserRole);
emit model->dataChanged(model->index(0,0), model->index(0,0), roles); // works. roles.count() == 2
}
MainWindow::myslot_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{
qDebug() << roles.count();
}
given Output:
0
0
2
expected Output:
1
1
2
I know that the roles QVector in the signal is optional. Could it somehow be possible that Qt omit the roles und just uses the default ones? Maybe I have to use the right signal (NOT the ones where you can omit the roles...) explicitely, but i dont know how.
Sorry for bad english, and thank you for help! ;)
Edit 1: Further Investigations:
I've crawled through the Qt sources and found this in qstandarditemmodel.cpp
void QStandardItem::setData(const QVariant &value, int role)
{
Q_D(QStandardItem);
role = (role == Qt::EditRole) ? Qt::DisplayRole : role;
QVector<QStandardItemData>::iterator it;
for (it = d->values.begin(); it != d->values.end(); ++it) {
if ((*it).role == role) {
if (value.isValid()) {
if ((*it).value.type() == value.type() && (*it).value == value)
return;
(*it).value = value;
} else {
d->values.erase(it);
}
if (d->model)
d->model->d_func()->itemChanged(this);
return;
}
}
d->values.append(QStandardItemData(role, value));
if (d->model)
d->model->d_func()->itemChanged(this);
}
When using setData the function itemChanged is used which does not care about the roles. It seems that the roles parameter in dataChanged is just optional for you and never used by native Qt functions.
Edit 2: even more investigations...
I stepped through the setData function. Here is the snippet when setData calls itemChanged():
void QStandardItemModelPrivate::itemChanged(QStandardItem *item)
{
Q_Q(QStandardItemModel);
Q_ASSERT(item);
if (item->d_func()->parent == 0) {
// Header item
int idx = columnHeaderItems.indexOf(item);
if (idx != -1) {
emit q->headerDataChanged(Qt::Horizontal, idx, idx);
} else {
idx = rowHeaderItems.indexOf(item);
if (idx != -1)
emit q->headerDataChanged(Qt::Vertical, idx, idx);
}
} else {
// Normal item
QModelIndex index = q->indexFromItem(item);
emit q->dataChanged(index, index);
}
}
As mentioned in the previous investigations setData calls itemChanged
which in turn calls emit q->dataChanged(index, index);
There we see dataChanged omits the role parameter. This means my previous guess, that Qt native functions dont use the roles, seems to be confirmed.
Upvotes: 1
Views: 2315
Reputation: 16856
From the docs of the signal QAbstractItemModel::dataChanged()
(emphasis by me):
void QAbstractItemModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = ...)
[...]
The optional roles argument can be used to specify which data roles have actually been modified. An empty vector in the roles argument means that all roles should be considered modified.
As you stated, Qt's implementation of QStandardItemModel
doesn't care to specify for which roles data changed, but instead specifies that all data should be updated.
The answer to the question (you didn't ask) is:
If your slot is called with a specific set of roles
, you can optimize for that. If roles
is empty, you need to fetch data for all roles that are relevant to your view.
Upvotes: 3