QStandardItemModel appendRow doesn't update QML TreeView


  • Lifetime Qt Champion

    What did you change in you subclass regarding QStandardItemModel ?



  • Nothing apart from custom roles I use in childEntry->setData.

    class ProjectTreeModel : public QStandardItemModel
    {
        Q_OBJECT
    public:
        explicit ProjectTreeModel(QObject *parent = 0);
        virtual ~ProjectTreeModel() = default;
    
        Q_INVOKABLE QString initializeModel(QString dirLoation);
        enum ProjectTreeModel_Roles
        {
            ProjectTreeModel_Role_Name = Qt::DisplayRole,
            ProjectTreeModel_Role_Type = Qt::WhatsThisRole,
            ProjectTreeModel_Role_Icon = Qt::DecorationRole
        };
    
        QHash<int, QByteArray> roleNames() const override;
    
    private:
        void addChildEntry( const QString& name, const QString& type, const QString& icon, QStandardItem parent);
        void addRootEntry( const QString& name, const QString& type, const QString& icon);
        QHash<int, QByteArray> m_roleNameMapping;
    };
    

    This is my class, so as you can see there is nothing really done with it.


  • Lifetime Qt Champion

    How/where are you appending rows outside the constructor ?



  • In the addRootEntry (and later in the addChildEntry where it should add a child to a given QStandardItem) in reaction to a button press.

    auto rootEntry = new QStandardItem( name );
    
        rootEntry->setData( icon, ProjectTreeModel_Role_Icon );
        rootEntry->setData( type, ProjectTreeModel_Role_Type );
        rootEntry->setData( name, ProjectTreeModel_Role_Name );
    
        invisibleRootItem()->appendRow(rootEntry);
    

    This is what it does.



  • Do I need to tell my view somehow that the model got updated?


  • Lifetime Qt Champion

    I'd emit dataChanged with the new index passing your custom roles.



  • I added emit dataChanged(QModelIndex(), QModelIndex(), roles); after my appendRow, which should update the whole view(?), but it still doesn't work.



  • This is my whole class right now, in case that helps:

    ProjectTreeModel::ProjectTreeModel(QObject *parent) :
        QStandardItemModel(parent)
    {
    
        m_roleNameMapping[ProjectTreeModel_Role_Name] = "name_role";
        m_roleNameMapping[ProjectTreeModel_Role_Type] = "type_role";
        m_roleNameMapping[ProjectTreeModel_Role_Icon] = "icon_role";
    
    
    }
    
    void ProjectTreeModel::addRootEntry( const QString& name, const QString& type, const QString& icon)
    {
        auto rootEntry = new QStandardItem( name );
    
        rootEntry->setData( icon, ProjectTreeModel_Role_Icon );
        rootEntry->setData( type, ProjectTreeModel_Role_Type );
        rootEntry->setData( name, ProjectTreeModel_Role_Name );
    
        invisibleRootItem()->appendRow(rootEntry);
        qDebug() << rootEntry;
        qDebug() << this->rowCount();
    
        QVector<int> vector(0);
        vector.append(ProjectTreeModel_Role_Icon);
        vector.append(ProjectTreeModel_Role_Type);
        vector.append(ProjectTreeModel_Role_Name);
    
        emit dataChanged(QModelIndex(), QModelIndex(), vector);
    }
    
    
    QHash<int, QByteArray> ProjectTreeModel::roleNames() const
    {
        return m_roleNameMapping;
    }
    

  • Lifetime Qt Champion

    AFAIK, no. You are passing two invalid indexes. If you want to trigger a refresh, give the top left and bottom right indexes of the part of the model that should get refreshed on the view.



  • Okay, tried it with emit dataChanged(invisibleRootItem()->index(), rootEntry->index(), vector); which should work, but it doesn't.



  • Or at least I think that should update everything from the root item to the newly created entry.


  • Lifetime Qt Champion

    How are you adding that new row outside the constructor ?



  • With the appendRow() method (on the invisible root item) as mentioned earlier.


  • Lifetime Qt Champion

    I meant, where are you calling appendRow ?



  • In a function that is called in response to a button click. (that function calls addRootItem multiple times)



  • What about using beginInsertRows() / endInsertRow() ?



  • That doesn't seem to work either.



  • Does anyone know of some piece of sample code for a dynamic model with Qt Quick and QStandardItemModel where you can add rows and edit items after the construction?



  • Oh, Damnit. I had a ProjectTreeViewModel { id:projecttreeviewmodel } in my UI components and used that instead of my treeviewmodel added as a context property.


  • Lifetime Qt Champion

    Sneaky one !

    Glad you found out :)