Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Treeview remove row



  • Tree model

    TreeModel::TreeModel(Context & aContext, QObject * parent)
      : QAbstractItemModel(parent)
      , mContext(aContext)
    
    {
    }
    
    TreeModel::~TreeModel()
    {
    }
    
    int TreeModel::rowCount(const QModelIndex & parent) const
    {
      const auto parentItem = getItem(parent);
    
      return parentItem ? static_cast<int>(parentItem->GetChildrenSize()) : 0;
    }
    
    int TreeModel::columnCount(const QModelIndex & parent) const
    {
      Q_UNUSED(parent);
      return mContext.GetRootClass()->GetNumberOfData();
    }
    
    QVariant TreeModel::data(const QModelIndex & index, int role) const
    {
      if (!index.isValid())
        return QVariant();
    
      if (role != Qt::DisplayRole && role != Qt::EditRole)
        return QVariant();
    
      auto item = getItem(index);
    
      if (index.column() == 0)
      {
        return QString::fromStdString(item->GetName());
      }
      else
      {
        return item->GetNumberOfStudents();
      }
    }
    
    Qt::ItemFlags TreeModel::flags(const QModelIndex & index) const
    {
      if (!index.isValid())
        return Qt::NoItemFlags;
    
      return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
    }
    
    QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
      if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
      {
        if (section == 0)
        {
          return QString("Class Name");
        }
        else if (section == 1)
        {
          return QString("Students");
        }
      }
      return QVariant();
    }
    
    bool TreeModel::setData(const QModelIndex & index, const QVariant & aClassData, int role)
    {
      if (role != Qt::EditRole)
        return false;
    
      auto item = getItem(index);
    
      switch (index.column())
      {
      case 0:
        item->SetName(aClassData.toString().toStdString());
        break;
      case 1:
        item->SetNumberOfStudents(aClassData.toInt());
        break;
      }
    
      emit dataChanged(index, index, { Qt::DisplayRole, Qt::EditRole });
    
      return true;
    }
    
    QModelIndex TreeModel::index(int row, int column, const QModelIndex & parent) const
    {
      if (parent.isValid() && parent.column() != 0)
        return QModelIndex();
    
      auto parentItem = getItem(parent);
      if (!parentItem)
        return QModelIndex();
    
      auto childItem = parentItem->GetChild(row);
      if (childItem)
        return createIndex(row, column, childItem);
      return QModelIndex();
    }
    
    QModelIndex TreeModel::parent(const QModelIndex & index) const
    {
      if (!index.isValid())
        return QModelIndex();
    
      auto childItem  = getItem(index);
      auto parentItem = childItem->GetParent();
    
      if (parentItem == mContext.GetRootClass() || !parentItem)
        return QModelIndex();
    
      return createIndex(static_cast<int>(parentItem->GetChildrenSize()), 0, parentItem);
    }
    
    Group * TreeModel::getItem(const QModelIndex & index) const
    {
      if (index.isValid())
      {
        Group * item = static_cast<Group *>(index.internalPointer());
        if (item)
          return item;
      }
    
      return mContext.GetRootClass();
    }
    
    bool TreeModel::insertRows(int position, int rows, const QModelIndex & parent)
    {
      // insert one row at position
      auto parentItem = getItem(parent);
      if (!parentItem)
        return false;
    
      beginInsertRows(parent, position, position + rows - 1);
      parentItem->AppendChild(mContext.GenerateClassId());
      endInsertRows();
    
      return true;
    }
    
    bool TreeModel::removeRows(int position, int rows, const QModelIndex & parent)
    {
      auto parentItem = getItem(parent);
      if (!parentItem)
        return false;
    
      beginRemoveRows(parent, position, position + rows - 1);
      parentItem->RemoveChild(position);
      endRemoveRows();
    
      return true;
    }
    
    -------------------------------------------- group.cpp -> tree nodes
    
    Group::Group(string aName, int aNumber, int aId, Group * aParent)
      : mName(aName)
      , mNumberOfStudents(aNumber)
      , mId(aId)
      , mParent(aParent)
    
    {
    }
    
    void Group::SetNumberOfStudents(int aNrOfStudent)
    {
      mNumberOfStudents = aNrOfStudent;
    }
    
    int Group::GetNumberOfStudents()
    {
      return mNumberOfStudents;
    }
    
    void Group::SetName(string aName)
    {
      mName = aName;
    }
    
    string Group::GetName()
    {
      return mName;
    }
    
    int Group::GetId()
    {
      return mId;
    }
    
    bool Group::operator==(const Group & aClass)
    {
      return mId == aClass.mId;
    }
    
    Group & Group::operator=(const Group & aClass)
    {
      if (this != &aClass)
      {
        this->mName             = aClass.mName;
        this->mNumberOfStudents = aClass.mNumberOfStudents;
        this->mId               = aClass.mId;
      }
    
      return *this;
    }
    
    Group::~Group()
    {
    }
    
    Group * Group::GetChild(int nr)
    {
      if (nr < 0 || nr >= mChildren.size())
        return nullptr;
      return mChildren.at(nr).get();
    }
    
    size_t Group::GetChildrenSize()
    {
      return mChildren.size();
    }
    
    int Group::GetNumberOfData()
    {
      // class name and number of students
      return 2;
    }
    
    void Group::AppendChild(int id)
    {
      unique_ptr<Group> newClass = make_unique<Group>("name", 0, id, this);
    
      mChildren.push_back(move(newClass));
    }
    
    Group * Group::GetParent()
    {
      return mParent;
    }
    
    void Group::RemoveChild(int pos)
    {
      if (pos < 0 || pos >= mChildren.size())
        return;
    
      mChildren.erase(mChildren.begin() + pos);
    }
    
    

    What I m doing wrong in this model? Sometimes not showing some nodes after I add more nodes, the other shows up but empty like setData was not called for them. And sometimes works just fine.



  • The first step in diagnosing a model is passing it through the model test. It usually tells you what you are doing wrong



  • The first step in diagnosing a model is passing it through the model test. It usually tells you what you are doing wrong



  • Qt 5.11 or later

    1. Add the QtTest module to your pro file like: QT += testlib
      How do I add this module in visual studio? I am not using qt creator and when i try to #include <QAbstractItemModelTester> i get this error "cannot open source file QAbstractItemModelTester "


  • I assume you have the Qt Visual Studio extension installed, if so right click on your project, go to qt project settings and, in the modules tab, tick Qt Test (remember to remove it once you are done)



  • Thank you very much, sir. Now I need to debug the errors. I don't get it, beside I use a unique_ptr to store nodes, the model and tree nodes are the same as in the qt tree model example.. Maybe someone has encountered this errors
    Screenshot (316).png Screenshot (317).png



  • Use the debugger to see what problems are being reported.
    The first screenshot is telling you that either your index() or parent() method are wrong (it checks that model->parent(model->index(row,column,idx))==idx

    The second screenshot is telling you your index() method is wrong. Passing a row, column and parent within the rowCount(parent) and columnCount(parent) constraints returns an invalid index. This is likely caused by you ignoring the parent argument in TreeModel::columnCount



  • Sir, do you have any link about qt debug in visual studio?


  • Lifetime Qt Champion

    @AlexandruToma said in Treeview remove row:

    Sir, do you have any link about qt debug in visual studio?

    Simply debug in Visual Studio. There is no such thing as "qt debug".



  • I got the same problem as in this topic.

    I changed columnCount function but the errors are still there

    int TreeModel::columnCount(const QModelIndex &parent) const
    {
       return (!parent.isValid() || parent.column() == 0) ? rootItem->columnCount() : 0;
    }
    

    I run tests on editable tree model in qt creator and I got the same error like in my project.

    Here is the error.

    // Common error test #3, the second column should NOT have the same children
    // as the first column in a row.
    // Usually the second column shouldn't have children.
    if (model->hasIndex(0, 1)) {
        QModelIndex topIndex1 = model->index(0, 1, QModelIndex());
        MODELTESTER_VERIFY(topIndex1.isValid());
        if (model->rowCount(topIndex) > 0 && model->rowCount(topIndex1) > 0) {
            QModelIndex childIndex = model->index(0, 0, topIndex);
            MODELTESTER_VERIFY(childIndex.isValid());
            ***QModelIndex childIndex1 = model->index(0, 0, topIndex1);***
            MODELTESTER_VERIFY(childIndex1.isValid());
            MODELTESTER_VERIFY(childIndex != childIndex1);
        }
    }


  • You are right, there is a bug in the example. I opened a ticket: https://bugreports.qt.io/browse/QTBUG-92178 the correct implementation should be:

    int TreeModel::rowCount(const QModelIndex &parent) const
    {
        if(parent.isValid() && parent.column()>0)
            return 0;
        const TreeItem *parentItem = getItem(parent);
        return parentItem ? parentItem->childCount() : 0;
    }
    


  • @VRonin said in Treeview remove row:

    if(parent.isValid() && parent.column()>0)
        return 0;
    const TreeItem *parentItem = getItem(parent);
    return parentItem ? parentItem->childCount() : 0;
    

    All good now. Thank you very much, sir.