How to modify the data in the model and update the view when new data is received from external?
-
@VInay123 said in How to modify the data in the model and update the view when new data is received from external?:
My class looks good:
It doesn't. as I mentioned above
@VRonin said in How to modify the data in the model and update the view when new data is received from external?:
CategoryItem& parentItem = currentItem->parentItem();
return createIndex(currentItem->row(), 0, &parentItem);This is using the address of a temp item, it will not work.
@VRonin: Oh.. How could this be fixed? I have to stick to QAbstractItemModel.
This is from Qt:
-
My row method was wrong and after updating i have a new failure in the test:
// Check that we can get back our real parent. //qDebug() << "TTT 1: " << model->parent(index); //qDebug() << "TTT 2: " << parent; //qDebug() << "TTT 3: " << index; tmp = model->parent(index); Q_ASSERT(tmp == parent);
At the above point i.e. line 375 its failing.
My old row function in item used to always give 1 which was wrong. Now i made it to look at the parent and find the position.int ScenarioPropertyItem::row() const { int count = parentItem_.entryCount(); for (int i = 0; i < count; i++) { if (this->displayName_ == parentItem_.entryAt(i)->displayName_) { return i; } } }
-
My row method was wrong and after updating i have a new failure in the test:
// Check that we can get back our real parent. //qDebug() << "TTT 1: " << model->parent(index); //qDebug() << "TTT 2: " << parent; //qDebug() << "TTT 3: " << index; tmp = model->parent(index); Q_ASSERT(tmp == parent);
At the above point i.e. line 375 its failing.
My old row function in item used to always give 1 which was wrong. Now i made it to look at the parent and find the position.int ScenarioPropertyItem::row() const { int count = parentItem_.entryCount(); for (int i = 0; i < count; i++) { if (this->displayName_ == parentItem_.entryAt(i)->displayName_) { return i; } } }
-
@VInay123 How can
parentItem_
not be a pointer? if you are taking a copy of the parent and store it in the child, you'll never go back to the old parent@VRonin: It is taken as reference to an unique_pointer. Now i have changed it as following:
QModelIndex Model::parent(const QModelIndex& index) const { if (!index.isValid()) { return QModelIndex(); } if (isCategory(index)) { return QModelIndex(); } const auto currentItem = static_cast<ScenarioPropertyItem*>(index.internalPointer()); CategoryItem* parentItem = currentItem->parentItem(); return createIndex(currentItem->row(), 0, parentItem); }
Please have a look at the index implementation also:
QModelIndex Model::index(int row, int column, const QModelIndex& parent /*= QModelIndex()*/) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } if (!parent.isValid()) { return createIndex(row, column, categories_.at(row).get()); } const auto currentCategory = static_cast<CategoryItem*>(parent.internalPointer()); ScenarioPropertyItem* currentItem = currentCategory->entryAt(row); if (currentItem) { return createIndex(row, column, currentItem); } else { return QModelIndex(); } }
Tried the test again but its failing at 340 at the same place:
I tried to comment in the debug output and i get the following:
-
This post is deleted!
-
@VRonin: It is taken as reference to an unique_pointer. Now i have changed it as following:
QModelIndex Model::parent(const QModelIndex& index) const { if (!index.isValid()) { return QModelIndex(); } if (isCategory(index)) { return QModelIndex(); } const auto currentItem = static_cast<ScenarioPropertyItem*>(index.internalPointer()); CategoryItem* parentItem = currentItem->parentItem(); return createIndex(currentItem->row(), 0, parentItem); }
Please have a look at the index implementation also:
QModelIndex Model::index(int row, int column, const QModelIndex& parent /*= QModelIndex()*/) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } if (!parent.isValid()) { return createIndex(row, column, categories_.at(row).get()); } const auto currentCategory = static_cast<CategoryItem*>(parent.internalPointer()); ScenarioPropertyItem* currentItem = currentCategory->entryAt(row); if (currentItem) { return createIndex(row, column, currentItem); } else { return QModelIndex(); } }
Tried the test again but its failing at 340 at the same place:
I tried to comment in the debug output and i get the following:
@VInay123 said in How to modify the data in the model and update the view when new data is received from external?:
I tried to comment in the debug output
Good. If you check it you realise that the problem is that
model->parent(index)
returns an item with row==1 while the original parent had row==0. that's because inparent()
you arereturn createIndex(currentItem->row(), 0, parentItem);
instead ofreturn createIndex(parentItem->row(), 0, parentItem);
-
@VInay123 said in How to modify the data in the model and update the view when new data is received from external?:
I tried to comment in the debug output
Good. If you check it you realise that the problem is that
model->parent(index)
returns an item with row==1 while the original parent had row==0. that's because inparent()
you arereturn createIndex(currentItem->row(), 0, parentItem);
instead ofreturn createIndex(parentItem->row(), 0, parentItem);
@VRonin Yes you are right, i have to fix it. Parent item does not have any parent so how should i save the position i.e. row for every parent? In my case the categories are parents, so i cant actually query the position in the class. One way i see is to save the row as member variable while creating the parent.
-
@VRonin Yes you are right, i have to fix it. Parent item does not have any parent so how should i save the position i.e. row for every parent? In my case the categories are parents, so i cant actually query the position in the class. One way i see is to save the row as member variable while creating the parent.
@VInay123 said in How to modify the data in the model and update the view when new data is received from external?:
One way i see is to save the row as member variable while creating the parent.
It's one way but usually it becomes unmanageable if you implement insert/remove/moveRows
You can always traverse
categories_
to find the index ofparentItem
-
@VInay123 said in How to modify the data in the model and update the view when new data is received from external?:
One way i see is to save the row as member variable while creating the parent.
It's one way but usually it becomes unmanageable if you implement insert/remove/moveRows
You can always traverse
categories_
to find the index ofparentItem
@VRonin: So now the test is running error free. This was the implementation i had to make:
QModelIndex Model::parent(const QModelIndex& index) const { if (!index.isValid()) { return QModelIndex(); } if (isCategory(index)) { return QModelIndex(); } const auto currentItem = static_cast<ScenarioPropertyItem*>(index.internalPointer()); CategoryItem* parentItem = currentItem->parentItem(); int rowNum = categories_.size(); for (int i = 0; i < rowNum; i++) { if (categories_.at(i)->displayName() == parentItem->displayName()) { rowNum = i; } } return createIndex(rowNum, 0, parentItem); }
But the view is still not displaying the new values. :( This is how i update the value
QModelIndex index = createIndex(1, 1, categories_[0]->entryAt(0)); this->setData(index, 11, Qt::EditRole);
My SetData:
bool Model::setData(const QModelIndex& index, const QVariant& value, int role /*= Qt::EditRole*/) { if (role == Qt::EditRole && index.column() == 1 && index.isValid()) { auto currentItem = static_cast<ScenarioPropertyItem*>(index.internalPointer()); if (currentItem) { currentItem->setValue(value); emit dataChanged(index, index); return true; } } return false; }
-
@VInay123 said in How to modify the data in the model and update the view when new data is received from external?:
But the view is still not displaying the new values
Does the view display the old values or is it completely empty? is
currentItem
null? -
@VInay123 said in How to modify the data in the model and update the view when new data is received from external?:
But the view is still not displaying the new values
Does the view display the old values or is it completely empty? is
currentItem
null?@VRonin: I initialize the model data i.e. categories_ with empty values. So the view shows empty value. But i update the value in my function and in debug mode i see the new value in the variable but the view shows empty i.e. old value. If i change the property to write mode, via delegate the value is being changed and view displays correctly. But when i do as following it does not:
QModelIndex index = createIndex(1, 1, categories_[0]->entryAt(0)); this->setData(index, 11, Qt::EditRole);
It actually calls the setData too and emits dataChanged. But the view is not displaying. Just for info my index method looks like this:
QModelIndex Model::index(int row, int column, const QModelIndex& parent /*= QModelIndex()*/) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } if (!parent.isValid()) { return createIndex(row, column, categories_.at(row).get()); } const auto currentCategory = static_cast<CategoryItem*>(parent.internalPointer()); ScenarioPropertyItem* currentItem = currentCategory->entryAt(row); if (currentItem) { return createIndex(row, column, currentItem); } else { return QModelIndex(); } }
-
What version of Qt are you on?
Usually the view ignores thedataChanged
if it thinks the cell pointed by index shouldn't exist@VRonin : I use Qt5.9.0. The update should have been this
QModelIndex index = createIndex(0, 1, categories_[0]->entryAt(0)); // but not 1,1 this->setData(index, 11, Qt::EditRole);
But even then after the above change its not updating. Actually in setData there is already a index.isValid() check. The indexes looks good and also the currentItem. Should i post my model and view once again after the new changes i have done?
-
@VRonin : I use Qt5.9.0. The update should have been this
QModelIndex index = createIndex(0, 1, categories_[0]->entryAt(0)); // but not 1,1 this->setData(index, 11, Qt::EditRole);
But even then after the above change its not updating. Actually in setData there is already a index.isValid() check. The indexes looks good and also the currentItem. Should i post my model and view once again after the new changes i have done?
@VInay123 said in How to modify the data in the model and update the view when new data is received from external?:
Actually in setData there is already a index.isValid() check.
index.isValid()
is an insufficient check, that's why checkIndex was introduced in Qt 5.11The indexes looks good and also the currentItem.
Unfortunately sometimes that's not enough. For example, if you forget to signal the view that you inserted a row, and then emit dataChanged for an item in that row, even if the item is 100% valid in the model the view will still think the row doesn't exist and do nothing
-
@JonB @VRonin @SGaist : Something is not seeming right. I tried first to change the value using the following:
QModelIndex index = createIndex(0, 1, categories_[0]->entryAt(0)); this->setData(index, 11, Qt::EditRole);
And in delegate class i tried to see what the value it has but it looks like it is zero. Below is the implementation:
QWidget *PropertyEditorItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (!index.isValid()) { return nullptr; } else if (index.column() == 0) { return QStyledItemDelegate::createEditor(parent, option, index); } const auto currentItem = static_cast<ScenarioPropertyItem *>(index.internalPointer()); switch (currentItem->itemType()) { case PropertyType::DOUBLE: { QDoubleSpinBox *box = new QDoubleSpinBox(parent); auto v = currentItem->data(index.column()); // Here it is zero??? :( box->setValue(v.toDouble()); return box; // qt will handle deletion } default: return QStyledItemDelegate::createEditor(parent, option, index); } }
-
In setData could you add the
qDebug
as below and tell us what is printed?if (currentItem) { currentItem->setValue(value); qDebug() << currentItem->data(1); qDebug() << index.data(Qt::DisplayRole); emit dataChanged(index, index); return true; }
@VRonin :
[16:56:03,236] [Debug] QVariant(int, 11) / My new values [16:56:03,237] [Debug] QVariant(int, 11) // My new values
;(
When i change via delegate:[16:58:06,173] [Debug] QVariant(double, 0) [16:58:06,176] [Debug] QVariant(double, 0)
I believe somewhere the indexes are not right. When i try to change the value(via delegate) of suppose "T" value so that i can iterate over parent and see the "S" value, here it is empty, but should be 11.
-
My model looks like this:
In parent method i use pointer for parent item but not reference.
-
@VRonin @SGaist @JonB : I just debugged to see that after changing the value of the property via delegate does the index in the following code has the same value.
QModelIndex index = createIndex(0, 1, categories_.at(0)->entryAt(0)); this->setData(index, 11, Qt::EditRole);
But it turns out that the index in the above is just a copy and when delegate changes the value it is not reflected in the index here. I think i am changing at a copy of the property but not the actual one.
-
This post is deleted!