Updating QTableView gives strange results



  • I have a multi-column QTableView that is populated from a QList and is updated every 10 seconds in case new elements are added to the list. To do the update I remove the rows then reinsert rows from the new list. However, there are times when I get weird results like more rows in the view than elements in the list, then on the next update things may be ok again. I have a feeling it has something to do with the way I'm removing rows and inserting the new ones but all my attempts to correct it have failed. Anyone have any suggestions. I have searched for examples but most all that I find are Sql examples or examples with 1 column. I have tried using the beginRemoveRows/beginInsertRows but I get an error because they are protected even though I'm using a standard model.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Without come code it will be difficult to guess what might be going wrong. Also, are you sure you are using QTableView and not QTableWidget ?



  • Did your subclass the model that holds the data? Or is it the basic QStandardTableModel? If so, you might need the appendRow() function to insert data into the model? Or use the takeRow() to remove an item.
    If your subclassing a QAbstractTableModel you should insert a setData() function for external change of data. In this function use the begin/endInsertRow option. When done emit the signal rowsInserted() and rowsremoved(index). Where ofcourse the index is the position in the table that was altered.
    Hope this helps a bit.
    Also read the pretty good model/view tutorial



  • Hi, and thanks for the welcome. I am using a table view and was not sure if it was the correct thing to use since other posts have shown using QTableWidget; while still other posts state that the Model/View approach is the way to go (I'm not so sure about that!).

    I'll try to put the code in that's relevant that should give you an idea of what I'm doing:

    -- this is the model setup
    proxyModel = new QSortFilterProxyModel( this );
    proxyModel->setDynamicSortFilter(true);

    //Get the data-model
    proxyModel->setSourceModel(getDataModel(this));
    

    QAbstractItemModel* MainWindow::getDataModel( QObject* parent )
    {
    //Instantiate the standard item model
    QStandardItemModel *model = new QStandardItemModel(parent);

    mHeaderListItems << "view type - hidden"
                     << "Authority\nNumber"
                     << "Block/Restriction\nType"
                     << "Device/Route\nName"
                     << "Apply\nDate/Time"
                     << "Remove\nDate/Time"
                     << "Controller's\nInitials"
                     << "Action"
                     << "Status";
    
    // set up the header data
    model->setHorizontalHeaderLabels( mHeaderListItems );
    
    return model;
    

    }

    void MainWindow::updateTable( QString text )
    {
    // clear the line items, refill the list, then
    mLineItemList.clear();

        // Convert the name to char* in order to pass it to te_subdivId
        QByteArray ba  = text.toLocal8Bit();
        char* subDivName = ba.data();
        int subdiv = te_subdivId( subDivName );
        
        fillTheList();
    
        int rowCount = ui->restrictionView->model()->rowCount();
        if( rowCount > 0 )
        {
            ui->restrictionView->model()->removeRows( 0, rowCount );
    
            -- this is code I tried but got an error about protected methods
            //proxyModel->beginRemoveRows( QModelIndex(), 0, rowCount );
            //proxyModel->removeRows( 0, rowCount );
            //proxyModel->endRemoveRows();
        }
        
    QListIterator<LineItem> j(mLineItemList);
    
    while( j.hasNext() )
    {
        LineItem li = j.next();
    
        proxyModel->insertRow(0);
        proxyModel->setData( proxyModel->index(0, VIEW_TYPE       ), li.authType );
        proxyModel->setData( proxyModel->index(0, AUTHORITY       ), li.auth );
        proxyModel->setData( proxyModel->index(0, RESTRICTION_TYPE), li.typeStr );
        proxyModel->setData( proxyModel->index(0, DEVICE          ), li.name );
        proxyModel->setData( proxyModel->index(0, DATE_APPLICATION), li.applyDt );
        proxyModel->setData( proxyModel->index(0, DATE_REMOVE     ), li.removeDt );
        proxyModel->setData( proxyModel->index(0, CONTROLLER_ID   ), li.applyID );
        proxyModel->setData( proxyModel->index(0, ACTION          ), li.action );
        proxyModel->setData( proxyModel->index(0, STATUS          ), li.status );
    
    }
    


  • Well I can see I didn't do a very good job of putting the code in my reply. First time I have posted code to a forum so, sorry about that.

    Thanks Jeron for your comment, I will investigate that further; I am using the standard model.



  • let's try the code again
    @
    --model setup
    proxyModel = new QSortFilterProxyModel( this );
    proxyModel->setDynamicSortFilter(true);

    //Get the data-model
    proxyModel->setSourceModel(getDataModel(this));
    

    QAbstractItemModel* MainWindow::getDataModel( QObject* parent )
    {
    //Instantiate the standard item model
    QStandardItemModel *model = new QStandardItemModel(parent);

    mHeaderListItems << "view type - hidden"
                     << "Authority\nNumber"
                     << "Block/Restriction\nType"
                     << "Device/Route\nName"
                     << "Apply\nDate/Time"
                     << "Remove\nDate/Time"
                     << "Controller's\nInitials"
                     << "Action"
                     << "Status";
    
    // set up the header data
    model->setHorizontalHeaderLabels( mHeaderListItems );
    
    return model;
    

    }

    void MainWindow::updateTable( QString text )
    {
    if( NULL != text )
    {
    // clear the line items, refill the list, then
    mLineItemList.clear();

        // Convert the name to char* in order to pass it to te_subdivId
        QByteArray ba  = text.toLocal8Bit();
        char* subDivName = ba.data();
        int subdiv = te_subdivId( subDivName );
        
        fillTheList();
    
        int rowCount = ui->restrictionView->model()->rowCount();
        if( rowCount > 0 )
        {
            ui->restrictionView->model()->removeRows( 0, rowCount );
    
            -- this gave me an error on protected methods
            //proxyModel->beginRemoveRows( QModelIndex(), 0, rowCount );
            //proxyModel->removeRows( 0, rowCount );
            //proxyModel->endRemoveRows();
        }
        
        this->insertRows();
    }
    
    ui->restrictionView->resizeColumnsToContents();
    ui->restrictionView->resizeRowsToContents();
    

    }

    void MainWindow::insertRows( void )
    {
    QListIterator<LineItem> j(mLineItemList);
    int i = 0;

    while( j.hasNext() )
    {
        LineItem li = j.next();
    
        proxyModel->insertRow(0);
        proxyModel->setData( proxyModel->index(0, VIEW_TYPE       ), li.authType );
        proxyModel->setData( proxyModel->index(0, AUTHORITY       ), li.auth );
        proxyModel->setData( proxyModel->index(0, RESTRICTION_TYPE), li.typeStr );
        proxyModel->setData( proxyModel->index(0, DEVICE          ), li.name );
        proxyModel->setData( proxyModel->index(0, DATE_APPLICATION), li.applyDt );
        proxyModel->setData( proxyModel->index(0, DATE_REMOVE     ), li.removeDt );
        proxyModel->setData( proxyModel->index(0, CONTROLLER_ID   ), li.applyID );
        proxyModel->setData( proxyModel->index(0, ACTION          ), li.action );
        proxyModel->setData( proxyModel->index(0, STATUS          ), li.status );
    }
    

    }

    @


  • Moderators

    You can update your individual posts with the three green fields ("edit", "move", "delete") at the bottom of each post. AFAIK at least the edit field you can see with your status.


  • Lifetime Qt Champion

    Since you are clearing your list, you can also call clear on your model, it'll be quicker.

    Don't use the proxy model to update your item model, use it directly.

    One thing you are doing wrong is that you add new rows, but you don't create the items for it (look "An example usage to create table" in the QStandardItemModel documentation)

    Hope it helps



  • Should I even be using the proxy model? I inherited this project and am very new to gui development so I did not know enough to determine whether this was the best way or not. Same thing with using QTableView vs QTableWidget.

    Looks like most implementations I've seen don't update the entire table every time, they just update the cell. If I understand things correctly, updating the entire table would involve creating new QStandardItem elements on every update.


  • Lifetime Qt Champion

    If you don't need sorting no. Otherwise, remove it until you get your table view working as you want it.

    What you should do is resize the table to fit the new size of your list, if necessary add new items. Then update the content of all the items.

    Since you need to refactor this code anyway, you should consider removing the getModel() function. Move the initialization in the constructor. You can be sure that someday someone will use it to create a new model several times when it's not needed.


Log in to reply
 

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