2

I have a QML TreeView like this:

  TreeView
  {
    id: treeview
    model: myModel
    anchors.fill: parent
    alternatingRowColors: false
    headerVisible: false

    TableViewColumn
    {
      title: "Name"
      role: "name"
      delegate: Text
      {
      text: styleData.value
      }
    }

However, when I emit dataChanged from a custom method in C++, nothing is updated:

void MyModel::NameChanged()
{
  // beginResetModel(); <=== Works
  // endResetModel();

  // emit dataChanged(QModelIndex(), QModelIndex()); // Does not work

  auto topLeftIndex = createIndex(0, 0, m_root.get());
  auto bottomRightIndex = createIndex(rowCount(), columnCount(), m_root.get());
  (( emit dataChanged(topLeftIndex, bottomRightIndex);  // Does not work.
  emit dataChanged(topLeftIndex, topLeftIndex);  // Does not work.
}

In QML, text is bound to styleData.value and I am not setting text anywhere else. Also, dataChanged is not redefined elsewhere. So I am sure I am really emitting QAbstractItemModel::dataChanged(...).

Any idea what I am doing wrong?

My index method:

QModelIndex index(int row, int column, const QModelIndex &parentIdx) const
{
  if (hasIndex(row, column, parentIdx) == false)
  {
    return QModelIndex();
  }

  auto parentItem = m_root.get();
  if (parentIdx.isValid() == true)
  {
    parentItem = static_cast<ModelItem *>(parentIdx.internalPointer());
  }

  auto childItem = parentItem->GetChild(row);
  auto childName = childItem->GetName().toStdString();
  if (childItem)
  {
    auto index = createIndex(row, column, childItem.get());
    return index;
  }
  else
  {
    return QModelIndex();
  }
}

My parent method:

QModelIndex parent(const QModelIndex &childIndex) const
{
  if (childIndex.isValid() == false)
  {
    return QModelIndex();
  }

  auto childItem = static_cast<ModelItem*>(childIndex.internalPointer());
  auto parentItem = childItem->GetParent();

  if (parentItem.expired() == true)
  {
    return QModelIndex();
  }

  auto pItem = parentItem.lock();
  if (pItem == nullptr)
  {
    return QModelIndex();
  }

  auto parentIndex = createIndex(pItem->GetRow(), 0, pItem.get());
  return parentIndex;
}

UPDATE: if I use my model in C++ using a QTreeView, then it works.

Korchkidu
  • 4,908
  • 8
  • 49
  • 69

1 Answers1

1

While beginResetModel() and endResetModel() will invalidate the whole view, dataChanged() only invalidates a range you give it.

If you know what value changed you can use it like

 emit dataChanged(createIndex(row,col),createIndex(row,col));

or when multiple lines/cells change the second parameter is the "last" index which changed.

Hayt
  • 5,210
  • 30
  • 37
  • I updated my question to test your suggestion. Please have a look. – Korchkidu Sep 14 '16 at 15:04
  • 1
    What does your `parent()` function return? the documentation says these indexes need to have the same parent. You should have one `dummy` element which acts as a parent for all other indexes. – Hayt Sep 15 '16 at 07:10
  • I have a dummy root. But as I am modifying some of its children, then I return an invalid QModelIndex (because their parent is the dummy root). This is the solution explained here: http://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html – Korchkidu Sep 15 '16 at 11:50
  • when do you return an invalid QModelIndex? Can you add your index() and your parent() function to your question? I would guess you somewhere have something wrong with your indexes. – Hayt Sep 15 '16 at 11:55
  • I added the index and parent method to my question. As display and reset are working fine, I never re-read them actually and considered they were fine. – Korchkidu Sep 15 '16 at 12:03
  • you seem to create a different parent item per row. so when you emit dataChanged across rows the rows each have a different parent. When you have one "dummy parent item" you should also just return the same index for it. – Hayt Sep 15 '16 at 12:07
  • "you seem to create a different parent item per row.". Can you give me more details please? Where do you see that? I am not sure I understood actually. Thanks. – Korchkidu Sep 15 '16 at 13:09
  • `auto parentIndex = createIndex(pItem->GetRow(), 0, pItem.get());` this creates a different parent index for each row. try `createIndex(0,0,...)` or so – Hayt Sep 15 '16 at 13:11
  • Each row (with the same parent), will return the same pItem. So pItem->GetRow() is the same (GetRow() returns the row of current element in its parent). – Korchkidu Sep 15 '16 at 13:48
  • Yes so each row has a different parent. and `dataChanged` is undefined if you pass indexes with different parent in them. – Hayt Sep 15 '16 at 13:49
  • If I do emit dataChanged(topLeftIndex, topLeftIndex);, it is not working as mentioned in my question. So even with the same index, it is not working. Also, other than updating when I internally set data, everything is working correctly. Also, I checked in a specific example, and even if I do createIndex(0, 0, pItem.get()); it is not working. – Korchkidu Sep 15 '16 at 14:06
  • I ended implemented this using a C++ QTreeView and it works fine. I have no idea why it is not working in QML though. – Korchkidu Sep 16 '16 at 17:17
  • @Hayt, I think you should update your answer with advice about the `parent()` function. – Piroxiljin May 23 '17 at 09:47
  • @Korchkidu I am not sure if child items are updated when you update your parent item (i.e. root item in your case). However, have you tried updating one specific item (that is not root)? This works for me – IceFire Dec 30 '18 at 10:46