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

QTableView alter data and sorting



  • Hi
    In my software data is loaded from files to QTableView.
    Sorting is enabled:
    tableView.setSortingEnabled(true);

    In another function I alter data from the level of the tableView
    (not by clicking on the choosen cell of the tableView but programmatically, see hereunder):

    tableView.model()->setData(indeks,
    QVariant(newCategory), Qt::EditRole);
    Before tableView.model()->setData...... I set sorting of the tableView : tableView.setSortingEnabled(false);
    and after changing data(using the function tableView.model()->setData......) again I set sotring
    of the tableView : tableView.setSortingEnabled(true);
    I changed data in the loop looking for the data I want to alter and after the loop has just been finished I set sorting: tableView.setSortingEnabled(true);

    If I have sorting set to false the function which change data works fine. But if the sorting is set to false and after changing data set to true the result of changing data are not correct.
    For exemple if I want to alter strings "AAA" to "BBB" only some
    part of them will change fexp 3 out of 4.
    Any sugestions please.


  • Lifetime Qt Champion

    Hi,

    What version of Qt are you using ?
    On what OS ?

    Can you provide a minimal compilable example that shows that behaviour ?



  • @SGaist
    Hi
    Qt Creator 4.7.1
    Based on Qt 5.11.2 (MSVC 2015, 32 bitowy)
    Version from Sep 18 2018 14:54:17
    From version fa50153fc8
    Os Windows 10 proffessional 64bit
    Example: not compilable but shows the matter.

    NowyMagazyn class derived from QAbstractItemModel.
    Virtual methods are overrided.
    The key issue here is why sorting makes problem when changin data.

    void NowyMagazyn::LoadMagazins()//Geting data from files to model and bring it to The View
    {
    //Getting names of the magazins
    QStringList nazwyMagazynow;
    nazwyMagazynow = cModel->GetMagazynNames();

    for(int i = 0; i < nazwyMagazynow.size(); i++)
    {     
      //Creating instance of the Magazin and pushBack to vectMagazin
      cMagazyn->CreateMagazynInstancesPushBackToVectMagazyn();
    
      ui->tabWidget->addTab(cMagazyn->GetVectMagazyn().at(i), nazwyMagazynow.at(i));
     
      //Creating Models for each Magazin
      cModel->CreateMagazynModelPushBackToVector();
      cModel->GetVectMagazynModel().at(i)->SetModelName(nazwyMagazynow.at(i));      
      cModel->GetVectMagazynModel().at(i)->InsertInvoker();
    
      //Creating FilterProxysModels
      cFilterProxyModel->CreateMagazynFilterProxyModelPushBackToVectFilterProxyModel();
      cFilterProxyModel->GetVectMagazynFilterProxyModel().at(i)->setSourceModel(cModel->GetVectMagazynModel().at(i));
     
      //Combine The View with The Model
      if(cMagazyn->GetVectMagazyn().size() > 0)
      {
          cMagazyn->GetVectMagazyn()[i]->GetTabView().setModel(cFilterProxyModel->GetVectMagazynFilterProxyModel().at(i));
          cMagazyn->GetVectMagazyn()[i]->GetTabView().setSortingEnabled(true);
          cMagazyn->GetVectMagazyn()[i]->GetTabView().horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
          cMagazyn->GetVectMagazyn()[i]->GetTabView().setSelectionBehavior(QAbstractItemView::SelectRows);
    
    
      }
    

    Now the function which change data in the View:

    void NowyMagazyn::UpdateViewAfterCategoryAlter(QString oldCategory, QString newCategory)
    {

    for(int i = 0; i < ui->tabWidget->count(); i++)
    {
        if(ui->tabWidget->tabText(i) == ui->CboxMagazyn->currentText())
        {            
            ui->tabWidget->setCurrentIndex(i); //The view has to be active before further actions           
            break;
        }
    }
    
    //before changing data in from the level of the view setting sorting to false
    cMagazyn->GetVectMagazyn().at(ui->tabWidget->currentIndex() - 2)->GetTabView().setSortingEnabled(false);
    
    //Getting rowCount 
    int rowCount = cMagazyn->GetVectMagazyn().at(ui->tabWidget->currentIndex() - 2)->GetTabView().model()->rowCount(QModelIndex());
    
    for(int i = 0; i <  rowCount; i++)
    {
        //Getting indekses one  by one for column 0
        QModelIndex indeks = cMagazyn->GetVectMagazyn().at(ui->tabWidget->currentIndex() - 2)->GetTabView().model()->index(i, 0);
    
        //Getting data from the view to compare
        QString categoryToCompare = cMagazyn->GetVectMagazyn().at(ui->tabWidget->currentIndex() - 2)->GetTabView().model() ->data(indeks).toString();
       
        
        //changing data in the view if comparission is true
        if(oldCategory == categoryToCompare)
         {
           cMagazyn->GetVectMagazyn().at(ui->tabWidget->currentIndex() - 2)->GetTabView().model()->setData(indeks,QVariant(newCategory), Qt::EditRole);                                       
           
         }
    }
    
    //after changing data  setting sorting to true;    
    cMagazyn->GetVectMagazyn()[ui->tabWidget->currentIndex() - 2]->GetTabView().setSortingEnabled(true);
    

    }

    See pictures before and after changing the data:0_1540703870144_Data befor changing.png 0_1540703888282_Data after changing.png

    I suspect that when changing data in the loop something goes wrong with indexes.
    See row 6 before changing data. The row moved to position 5 after changing the data.
    One of the solution to get rid of the problem is to break the loop in the if statement
    and call UpdateViewAfterCategoryAlter(ui->CboxKategoria->currentText(), nowaNazwaKategorii); function so many times how many we have rows with data to change:
    exp:
    for(int i = 0; i < number of rows to change; i++)
    UpdateViewAfterCategoryAlter(ui->CboxKategoria->currentText(), nowaNazwaKategorii);

    and breaking the loop in the if statement in UpdateViewAfterCategoryAlter:

        //changing data in the view if comparission is true
        if(oldCategory == categoryToCompare)
         {
           cMagazyn->GetVectMagazyn().at(ui->tabWidget->currentIndex() - 2)->GetTabView().model()->setData(indeks,QVariant(newCategory), Qt::EditRole);
           break;
         }

  • Lifetime Qt Champion

    Your code is very hard to read. Why to you call "cMagazyn->GetVectMagazyn().at(ui->tabWidget->currentIndex() - 2)->GetTabView().model()" every time instead using an intermediate variable?

    auto model = cMagazyn->GetVectMagazyn().at(ui->tabWidget->currentIndex() - 2)->GetTabView().model();
    for (int i = 0; i < model->rowCount(); ++i) {
      const auto idx = model->index(i, 0);
      const QString categoryToCompare  = model->data(idx, Qt::EditRole).toString();
      if (oldCategory == categoryToCompare)
        model->setData(idx, newCategory), Qt::EditRole);
    }
    

    And notw to your problem - since you've enabled sorting the sorting will occur as soon as you call setData() which also means that your row indexes will change.



  • Yes indeed it is a little hard to read. Good idea with intermmediate variable.
    You write: "And not to your problem - since you've enabled sorting the sorting will occur as soon as you call setData() which also means that your row indexes will change."
    I agree.
    Before changing the data sorting is disabled and only after changing them sotring is enabled. I add that if sorting is disabled at all the function works fine.
    It is quite odd.


  • Lifetime Qt Champion

    @Slawomir_Piernikowski said in QTableView alter data and sorting:

    cFilterProxyModel

    Since you've a custom QSortFilterProxyModel inbetween you can't simply disable sorting this way - this property is only usefull to enable/disable sorting by the user. I first was under the impression that you're using a QTableWidget



  • So how can it be done???. I add that I have not overrided sort function in MagazynModel which derived from QAbstractItemModel and not overrided sort function in MagazynFilterProxyModel which derived from QSortFilterProxyModel. I use only QSortFilterProxyModel for filtring data.
    I say again that when tabView->SetSortingEnabled(bool) is never set true in my soft
    the UpdateViewAfterCategoryAlter works fine (data after changing are correct) and there is no any sorting.


  • Lifetime Qt Champion

    You can e.g. iterate over the base model. There the rows won't change it's order.



  • Yes it can be done like this.
    In Model View Control you can change data by clicking on the selected data in a cell and change data - this works ok.

    I have tried to do the same but changing data in many cell one by one using loop - this only works when setSortingEnabled is never set true in the soft.

    So I jumpet to a conclusion to break the loop just after changing the data in one cell
    and again call the function UpdateViewAfterCategoryAlter again and again up to the number data in cell(rows) I wanted to change - this works ok even SetSortingEnabled(true).

    I was googling for information and found out that just before changing data sorting should be set false an just after should be set to true but in my case it is not working. I submited the post here because maybe somebody had the same issue.


  • Lifetime Qt Champion

    @Slawomir_Piernikowski said in QTableView alter data and sorting:

    I was googling for information and found out that just before changing data sorting should be set false an just after should be set to true but in my case it is not working

    This is true for the convenience QTableWidget but not when you have a custom QSortFilterProxyModel inbetween. Then you can do it like I suggested - directly change the values in the source model.



  • Ok I got it. Thanks
    I have decided to change data using the View instead of the model. Simply it is easyer to do.

    "So I jumpet to a conclusion to break the loop just after changing the data in one cell
    and again call the function UpdateViewAfterCategoryAlter again and again up to the number data in cell(rows) I wanted to change - this works ok even SetSortingEnabled(true)."

    ...but after testing this solution with 1000 strings(located in one column) to change I have noticed that it takes much time to do this and soft crashes itself.

    So I come back to do the same with the source model and this approach apeard to be better one.
    That means works faster and more stable.


Log in to reply