How to update QTableView when rows are inserted to it



  • I am trying to insert rows to QTableView set to QAbstractTableModel using drag of item from another TreeView on to the QTableView.

       //Constructor of Tableview 
        model= new TableModel();
        TableRowCount=0;
        model->rCount=TableRowCount;
        this->setModel(model);
        setAcceptDrops(true);
    
       //dropEvent
            QTreeView * view= dynamic_cast<QTreeView*>(event->source());
            QModelIndexList list= view->selectionModel()->selectedIndexes();
            for(int i=0;i<list.count();i++)
            {
                QModelIndex dragIndex=list.at(i);
                if(dragIndex.parent().isValid())
                {
                    TableRowCount++;
                   model->rCount=TableRowCount;
                    
                    TableStruct Tstruct;
                    Tstruct.DeviceName=dragIndex.parent().data(Qt::DisplayRole).toString();
                    Tstruct.MessageName=dragIndex.parent().data(Qt::DisplayRole).toString();
                    Tstruct.TagName=dragIndex.data(Qt::DisplayRole).toString();
                    Tstruct.Value=QString::number(0);
                    Tstruct.Units=QString::number(0);
                    
                    TableStrList.append(Tstruct);
                    model->TableList=TableStrList;
                    model->insertRows(TableRowCount,1,dragIndex);
    

    And model looks like

    QVariant Model::data(const QModelIndex &index, int role) const
    {
        if (role == Qt::DisplayRole)
        {
            int column = index.column();
            int row  = index.row();
    
            switch(column)
            {
            case 0:
                return   TableList.at(row).DeviceName;
                break;
            case 1:
                return   TableList.at(row).MessageName;
                break;
            case 2:
                return   TableList.at(row).TagName;
                break;
            case 3:
                return   TableList.at(row).Value;
                break;
            case 4:
                return   TableList.at(row).Units;
                break;
            }
        }
    
        if(role == Qt::TextAlignmentRole)
        {
            return Qt::AlignCenter;
        }
    
        return QVariant();
    }
    
    int Model::rowCount(const QModelIndex & /*parent*/) const
    {
        qDebug()<< "row count "<<rCount;
        return rCount;
    }
    
    int Model::columnCount(const QModelIndex & /*parent*/) const
    {
        return 5;
    }
    
    QVariant Model::headerData( int section,Qt::Orientation orientation,int role ) const
    {
        if((role == Qt::DisplayRole || role ==Qt::ToolTipRole))
        {
            if(orientation == Qt::Horizontal)
            {
                switch( section )
                {
                case 0: return( QString( "Device Name" ) );
                case 1: return( QString( "Message Name" ) );
                case 2: return( QString( "Tag Name" ) );
                case 3: return( QString( "Value" ) );
                case 4:return (QString("units"));
                }
            }
        }
        return QAbstractItemModel::headerData( section, orientation, role );
    }
    
    bool Model::insertRows(int row, int count, const QModelIndex &parent)
    {
        beginInsertRows(parent,row,row+count-1);
        endInsertRows();
        return true;
    }
    

    Row count in the model is updated properly on drop of item but the view is not getting updated. How will the will know that the new rows re inserted??


  • Qt Champions 2016

    @Ratzz
    Hello,
    I believe you should emit the QAbstractItemModel::rowsInserted signal from the model (after your call to endInsertRows), so the view knows to adapt to the changes.

    Kind regards.


    PS:

    switch(column)
    {
        case 0:
    

    You should really use (possibly unnamed) enums for that kind of switch constructs.



  • @kshegunov
    Thanks for the reply.
    But doc says

    Note: This is a private signal. It can be used in signal connections but cannot be emitted by the user.
    

    What does this mean?


  • Qt Champions 2016

    @Ratzz
    It means it can't be emitted from the user of the class. Since you're not the user of the class, but rather the designer, I think you should just ignore the note. ;)



  • @kshegunov
    It asks for QPrivateSignal http://postimg.org/image/bjpuc4bep/


  • Qt Champions 2016

    @Ratzz
    Oops, sorry. The note above the one you cited states:

    It can only be emitted by the QAbstractItemModel implementation, and cannot be explicitly emitted in subclass code.
    

    Hm, in that case I'm not sure ... The documentation is somewhat cryptic whether endInsertRows() actually emits the aforementioned signal ...


  • Qt Champions 2016

    @Ratzz
    Possibly, you could try implementing QAbstractItemModel::dropMimeData without intercepting the drop event?



  • @kshegunov
    The beginInsertRows doc http://doc.qt.io/qt-4.8/qabstractitemmodel.html#beginInsertRows says

    Note: This function emits the rowsAboutToBeInserted() signal which connected views (or proxies) must handle before the data is inserted. Otherwise, the views may end up in an invalid state.
    

    Will it help?


  • Qt Champions 2016

    @Ratzz
    Yes, I saw that, but this is to notify the view insertions will be happening. The question is whether endInsertRows() emits rowsInserted() thus telling the view the insertion has finished and it can actually update itself. Unfortunately, the documentation doesn't state anything specific about endInsertRows(), unless I completely missed it ...

    PS. I just noticed something in your code:

    QTreeView * view= dynamic_cast<QTreeView*>(event->source());
    

    Is this a typo?


  • Lifetime Qt Champion

    Hi,

    The documentation doesn't specify but the implementation does emit rowsInserted. However in this case insertRows doesn't do anything so I wonder if there isn't a caching mechanism that avoids to update the view if in fact nothing has changed.



  • @kshegunov said:

    Is this a typo?

    I drag the items from another QTreeView .The cast is for that..
    Did you mean that?



  • @SGaist said:
    Thanks for the reply.
    So there is no way with insertRows?


  • Qt Champions 2016

    @SGaist

    However in this case insertRows doesn't do anything so I wonder if there isn't a caching mechanism that avoids to update the view if in fact nothing has changed.

    After a quick look (without pretense to be complete) I couldn't clearly see any such caching done.
    Here's what I peeked at (for Qt 5.6):
    http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/itemmodels/qabstractitemmodel.cpp#n2601
    http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/itemmodels/qabstractitemmodel.cpp#n582

    @Ratzz

    I drag the items from another QTreeView .The cast is for that..
    Did you mean that?

    Indeed I did. Have you considered handling the drag/drop events through the ordinary mechanism? Serializing on drag, then deserializing the mime data on drop?



  • @kshegunov said:

    Serializing on drag, then deserializing the mime data on drop?

    No i have not considered this part.


  • Lifetime Qt Champion

    @kshegunov : I mean't view side caching.

    @Ratzz currently you are not inserting anything through it. Like @kshegunov suggested, implement the drag and drop through the mechanism provided for model/view classes. It's described here



  • @SGaist
    I will try to implement through (link you provided ) this.


  • Qt Champions 2016

    @Ratzz

    No i have not considered this part.

    Then I suggest you try it out. It may prove to be easier and better behaved than pulling the records directly from the tree widget. As for your current implementation, I'm at a loss why it doesn't work. Maybe the tree view is losing the selection when dragging and the selection model returns no records?

    @SGaist

    I mean't view side caching.

    I see, well I didn't look at the view (obviously) but I suppose it's possible.


  • Qt Champions 2016

    Hi
    I am still wondering. Sorry.
    Lets say If I dont have drag&drop.

    I simply append to my internal list used in model.

    How will I tell the view(s) that?

    I though dataChanged would do it but not even begin/endInsertRow
    does it.

    Thanks



  • @kshegunov said:

    Maybe the tree view is losing the selection when dragging and the selection model returns no records?

    I don't think so because the rowCount is getting updated as and when the new drop takes place.


  • Qt Champions 2016

    @mrjj

    I simply append to my internal list used in model.

    I'm by no means an expert, but possibly calling submit() (I don't know if it works I'm just guessing)?


  • Lifetime Qt Champion

    On a side note, your rowCount implementation should rather return the size of your TableList, that way it's one less thing to manage.



  • @SGaist
    Yes ,now i am returning the size of TableList .



  • In dropEvent called a new function from model which stores all the parameter of item when droped and emitted layoutAboutToBeChanged() before appending to my TableList and then emitted layoutChanged() which worked for me.

    Thanks to @kshegunov , @SGaist , @mrjj for the help.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.