Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. insert row into QSqlTableModel from QAbstractProxyModel(TreeModel)
Forum Updated to NodeBB v4.3 + New Features

insert row into QSqlTableModel from QAbstractProxyModel(TreeModel)

Scheduled Pinned Locked Moved Solved General and Desktop
9 Posts 4 Posters 1.6k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    sadeq
    wrote on last edited by sadeq
    #1

    I have subclassed QAbstractProxyModel to make a Treemodel out of a QSqlTableModel
    the SQL table structure is
    category,ID,parentID
    ID is autoincrement
    if parentID=0 then it's a root category

    the model works fine in viewing the Data in a tree structure but I'm having a trouble in inserting rows
    I have no clue about how to do it
    I tried something like

    
           QSqlTableModel *mdl= static_cast<QSqlTableModel *>(sourceModel());
           QSqlRecord record=mdl->record();
           record.setValue(0,"category");
           record.setValue(2,0); //parentID is 0 so it's a root category
           mdl->insertRecord(-1,record)
            mdl->select();
           emit layoutChanged();
    

    I've also tried reimplementing insertRows() and using beginInsertRows() and endInsertRows() while inserting the record between the calls but none of the solutions above worked the way I expected
    the record is inserted into the sourceModel and the Database but the proxyModel either updates and puts the new row in the wrong index or replaces an existing row
    if I restart the APP everything is displayed fine until I begin inserting rows

    so what is the correct way to inform the proxymodel that the sourceModel changed ?

    qsqltreemodel.h

    #ifndef QSQLTREEMODEL_H
    #define QSQLTREEMODEL_H
    #include <QAbstractProxyModel>
    
    
    class QSqlTreeModel : public QAbstractProxyModel
    {
        Q_OBJECT
    public:
        QSqlTreeModel(QObject *parent=nullptr);
        virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
        virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
        virtual QModelIndex parent(const QModelIndex &child) const;
    
        virtual QModelIndex index(int row, int column, const QModelIndex &parent) const;
        virtual int rowCount(const QModelIndex &parent) const;
        virtual int columnCount(const QModelIndex &parent) const { return sourceModel()->columnCount(parent); }
    
        virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const { return sourceModel()->headerData(section,orientation,role); }
        virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) { return sourceModel()->setHeaderData(section,orientation,value,role); }
    
        virtual bool hasChildren(const QModelIndex &parent) const;
        virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
    
    
    
    
    private:
    
        int getParentId(int childId) const;
    
        int childNumber(int ID) const;
        int GetID(int ParentID, int row) const;
        int  IDColumn=1;
        int pIDColumn=2;
        int DataColumn=0;
       
    
    
    };
    
    #endif // QSQLTREEMODEL_H
    

    qsqltreemodel.cpp

    #include "qsqltreemodel.h"
    #include <QSqlTableModel>
    #include <QDebug>
    QSqlTreeModel::QSqlTreeModel(QObject *parent) : QAbstractProxyModel(parent)
    {
    
    }
    
    QModelIndex QSqlTreeModel::mapFromSource(const QModelIndex &sourceIndex) const
    {
        if(!sourceIndex.isValid())
            return QModelIndex();
    
        int id = (sourceIndex.column() == IDColumn) ? sourceIndex.data().toInt() : sourceIndex.siblingAtColumn(IDColumn).data().toInt();    
        int row=childNumber(id);
        return createIndex(row, sourceIndex.column(), id);
        //return index(row,sourceIndex.column(),QModelIndex());
    }
    
    QModelIndex QSqlTreeModel::mapToSource(const QModelIndex &proxyIndex) const {
        if(!proxyIndex.isValid())
            return QModelIndex();
        int id = proxyIndex.internalId();
        int row = -1;
    
        for(int i=0 ; i<sourceModel()->rowCount() ; i++)
            if(sourceModel()->index(i,IDColumn).data().toInt()==id)
            {
                row=i;
                break;
            }
        return sourceModel()->index(row, proxyIndex.column());
    }
    
    bool QSqlTreeModel::hasChildren(const QModelIndex &parent) const
    {
        int ID=parent.internalId();
        for(int i=0; i<sourceModel()->rowCount() ; i++)
            if(sourceModel()->index(i,pIDColumn).data().toInt()==ID)
                return true;
    
        return false;
    }
    
    QModelIndex QSqlTreeModel::parent(const QModelIndex &child) const
    {
        int childId  = child.internalId();
        int parentId = getParentId(childId);
        if(parentId == 0)
            return QModelIndex();
        int parentRow =childNumber(parentId);
        return createIndex(parentRow, child.row(), parentId);
    }
    
    QModelIndex QSqlTreeModel::index(int row, int column, const QModelIndex &parent) const
    {
        if(row < 0 || column < 0)
            return QModelIndex();
    
        int id=GetID(parent.internalId(),row);
        return createIndex(row, column, id);
    }
    
    int QSqlTreeModel::rowCount(const QModelIndex &parent) const
    {
        int ID=0;
        if(parent.isValid())
            ID=parent.internalId();
    
        int count=0;
        for(int i=0 ; i<sourceModel()->rowCount() ; i++)
            if(sourceModel()->index(i,pIDColumn).data().toInt()==ID)
                count++;
    
        return count;
    }
    
    int QSqlTreeModel::getParentId(int childId) const
    {
        for(int i=0; i<sourceModel()->rowCount() ; i++)
            if(sourceModel()->index(i,IDColumn).data().toInt()==childId)
                return sourceModel()->index(i,pIDColumn).data().toInt();
    
        return -1; //remove
    }
    
    
    int QSqlTreeModel::childNumber(int ID) const
    {
        int ParentID=getParentId(ID);
        int n=-1;
        for(int i=0 ; i<sourceModel()->rowCount() ; i++)
        {
            if(sourceModel()->index(i,pIDColumn).data().toInt()==ParentID)
            {
                n++;
                if(sourceModel()->index(i,IDColumn).data().toInt()==ID)
                    break;
            }
        }
        return n;
    }
    
    
    
    int QSqlTreeModel::GetID(int ParentID,int row) const
    {
        int count=-1;
        for(int i=0 ; i<sourceModel()->rowCount() ; i++)
        {
            if(sourceModel()->index(i,pIDColumn).data().toInt()==ParentID)
                count++;
            if (count==row)
                return sourceModel()->index(i,IDColumn).data().toInt();
        }
        return -1; //remove this
    }
    
    
    
    Qt::ItemFlags QSqlTreeModel::flags(const QModelIndex &index) const
    {
        if(index.isValid())
        {
            return (Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
        }
    
    
            return 0;
    }
    
    
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi and welcome to devnet,

      Why are you modifying the source model within the proxy ? That's rather fishy.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      S 1 Reply Last reply
      1
      • SGaistS SGaist

        Hi and welcome to devnet,

        Why are you modifying the source model within the proxy ? That's rather fishy.

        S Offline
        S Offline
        sadeq
        wrote on last edited by sadeq
        #3

        @SGaist
        what I'm trying to create is a complete proxy model that takes a flat SQL table(through QSqlTableModel) and turns it into a Tree Model so that I can use it in QTreeView
        the proxyModel must be able to perform all the operations that QSqlTableModel can do(view,insert,remove,modify)
        so far with the code above I can view the model and modify the data from the QTreeView
        I didn't even need to subclass setData() function to be able to modify the data
        the only thing that was needed is to pass Qt::ItemIsEditable flag
        the only operations left are insert and remove rows
        I guess remove rows is easy even though I haven't tried it yet, but inserting rows is a little bit difficult
        how do use suppose to modify the source model then ?
        i know I can modify the source from outside but the proxy just won't update

        JonBJ 1 Reply Last reply
        0
        • S sadeq

          @SGaist
          what I'm trying to create is a complete proxy model that takes a flat SQL table(through QSqlTableModel) and turns it into a Tree Model so that I can use it in QTreeView
          the proxyModel must be able to perform all the operations that QSqlTableModel can do(view,insert,remove,modify)
          so far with the code above I can view the model and modify the data from the QTreeView
          I didn't even need to subclass setData() function to be able to modify the data
          the only thing that was needed is to pass Qt::ItemIsEditable flag
          the only operations left are insert and remove rows
          I guess remove rows is easy even though I haven't tried it yet, but inserting rows is a little bit difficult
          how do use suppose to modify the source model then ?
          i know I can modify the source from outside but the proxy just won't update

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #4

          @sadeq
          I'm not an expert, like @SGaist is, and haven't followed your code! But one thought: when your new row is committed to the database it gets an auto-incremented, unique ID. Where do you generate this before commit/refresh? If your view is sorted by ID this will matter, won't it?

          S 1 Reply Last reply
          1
          • VRoninV Offline
            VRoninV Offline
            VRonin
            wrote on last edited by
            #5

            I built something like this in the past: https://github.com/VSRonin/QtModelCategorizer

            It was plagued by a bug in a specific use case but now I totally forgot what it was.
            Feel free to give it a try, if you find out what the bug was open a ticket in github please

            "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
            ~Napoleon Bonaparte

            On a crusade to banish setIndexWidget() from the holy land of Qt

            S 1 Reply Last reply
            2
            • JonBJ JonB

              @sadeq
              I'm not an expert, like @SGaist is, and haven't followed your code! But one thought: when your new row is committed to the database it gets an auto-incremented, unique ID. Where do you generate this before commit/refresh? If your view is sorted by ID this will matter, won't it?

              S Offline
              S Offline
              sadeq
              wrote on last edited by
              #6

              @JonB
              the ID is generated automatically since I left the ID field blank
              see, I didn't type "record.setValue(1,ID);" so field 1(ID field) will be null an it will be generated when I call
              "mdl->insertRecord(-1,record)"
              the proxyModel itself has no sorting capabilities, but the SQL table is sorted by the autoincremented ID

              1 Reply Last reply
              0
              • VRoninV VRonin

                I built something like this in the past: https://github.com/VSRonin/QtModelCategorizer

                It was plagued by a bug in a specific use case but now I totally forgot what it was.
                Feel free to give it a try, if you find out what the bug was open a ticket in github please

                S Offline
                S Offline
                sadeq
                wrote on last edited by
                #7

                @VRonin
                that's really nice, looking at the source, it's quite a complected implementation, I'll try it out when I have the time and see how you Implemented some of the methods

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  sadeq
                  wrote on last edited by
                  #8

                  I solved it guys, all I had to do was disable sorting in the QTreeView and emit layoutChanged(); after insertRecord(-1,record); and select(); and everything worked fine
                  now whenever I insert a row it is inserted at the end and it doesn't override any existing row

                  JonBJ 1 Reply Last reply
                  0
                  • S sadeq

                    I solved it guys, all I had to do was disable sorting in the QTreeView and emit layoutChanged(); after insertRecord(-1,record); and select(); and everything worked fine
                    now whenever I insert a row it is inserted at the end and it doesn't override any existing row

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by JonB
                    #9

                    @sadeq
                    I think you'll find somewhere in the documentation that you always have to disable sorting in a model/proxy before you do any inserts which include a "position row", else it goes wrong.

                    1 Reply Last reply
                    2

                    • Login

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved