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

QStandardItemModel appendRow doesn't update QML TreeView



  • Hey, adding an item into my subclassed QStandardItemModel works perfectly fine when using appendRow in the constructor of the model, however it works nowhere else. The items are to the model when added to the invisibleRootItem, but they are not shown in the tree. Do I need to update the TreeView manually somehow?



  • No idea?


  • Lifetime Qt Champion

    Hi,

    Please practice some patience, allow 24 hours before bumping your own thread. Not all people on this forum live in the same timezone as you.

    Did you follow the example about [Inserting and removing rows](http://doc.qt.io/qt-5/model-view-programming.html ?



  • I guess? Do I need to reimplement insertRows? If so, how does that work for my QStandardItems?


  • 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 :)