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. How to sort original data structure of QAbstractTableModel?
Forum Updated to NodeBB v4.3 + New Features

How to sort original data structure of QAbstractTableModel?

Scheduled Pinned Locked Moved Solved General and Desktop
20 Posts 4 Posters 2.5k Views
  • 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.
  • C Offline
    C Offline
    CuriousPan
    wrote on last edited by CuriousPan
    #8

    Okay, here's the code:

    //m_model is a ForecastingProxyModel class inheriting from QAbstractTableModel
    ForecastingProxyModel *proxyModel = new ForecastingProxyModel(this);
    proxyModel->setSourceModel(m_model);
    ui->forecastingTableView->setModel(proxyModel);
    ui->forecastingTableView->setSortingEnabled(true);
    

    Here's the code of the lessThan of the QSortFilterProxyModel:

    bool ForecastingProxyModel::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const
    {
        const QVariant &leftData = sourceModel()->data(sourceLeft);
        const QVariant &rightData = sourceModel()->data(sourceRight);
        //sourceModel()->sort(sourceLeft.column(), sortOrder());  you said it's a bad idea to call it hear.
    
        if (leftData.userType() == QMetaType::QDate) {
            return leftData.toDate() < rightData.toDate();
        } else if (leftData.userType() == QMetaType::QString) {
            return leftData.toString() < rightData.toString();
        } else if (leftData.userType() == QMetaType::Double) {
            return leftData.toDouble()  < rightData.toDouble();
        } else if (leftData.userType() == QMetaType::Bool) {
            return leftData.toBool() < rightData.toBool();
        }
    
        return QSortFilterProxyModel::lessThan(sourceLeft, sourceRight);
    }
    

    Here's a sort method of the source model:

    void ForecastingModel::sort(int column, Qt::SortOrder order)
    {
        switch(column) {
        case Name:
            if (order == Qt::AscendingOrder) {
                std::sort(m_logicController->forecasts().begin(), m_logicController->forecasts().end(),
                          [](const Forecast &a, const Forecast &b) { return a.name < b.name; });
            } else {
                std::sort(m_logicController->forecasts().begin(), m_logicController->forecasts().end(),
                          [](const Forecast &a, const Forecast &b) { return a.name > b.name; });
            }
            break;
    
        case Price:
            if (order == Qt::AscendingOrder) {
                std::sort(m_logicController->forecasts().begin(), m_logicController->forecasts().end(),
                          [](const Forecast &a, const Forecast &b) { return a.price < b.price; });
            } else {
                std::sort(m_logicController->forecasts().begin(), m_logicController->forecasts().end(),
                          [](const Forecast &a, const Forecast &b) { return a.price > b.price; });
            }
            break;
        }
    }
    

    Is it enough or something more is required?

    JonBJ Christian EhrlicherC 2 Replies Last reply
    0
    • C CuriousPan

      Okay, here's the code:

      //m_model is a ForecastingProxyModel class inheriting from QAbstractTableModel
      ForecastingProxyModel *proxyModel = new ForecastingProxyModel(this);
      proxyModel->setSourceModel(m_model);
      ui->forecastingTableView->setModel(proxyModel);
      ui->forecastingTableView->setSortingEnabled(true);
      

      Here's the code of the lessThan of the QSortFilterProxyModel:

      bool ForecastingProxyModel::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const
      {
          const QVariant &leftData = sourceModel()->data(sourceLeft);
          const QVariant &rightData = sourceModel()->data(sourceRight);
          //sourceModel()->sort(sourceLeft.column(), sortOrder());  you said it's a bad idea to call it hear.
      
          if (leftData.userType() == QMetaType::QDate) {
              return leftData.toDate() < rightData.toDate();
          } else if (leftData.userType() == QMetaType::QString) {
              return leftData.toString() < rightData.toString();
          } else if (leftData.userType() == QMetaType::Double) {
              return leftData.toDouble()  < rightData.toDouble();
          } else if (leftData.userType() == QMetaType::Bool) {
              return leftData.toBool() < rightData.toBool();
          }
      
          return QSortFilterProxyModel::lessThan(sourceLeft, sourceRight);
      }
      

      Here's a sort method of the source model:

      void ForecastingModel::sort(int column, Qt::SortOrder order)
      {
          switch(column) {
          case Name:
              if (order == Qt::AscendingOrder) {
                  std::sort(m_logicController->forecasts().begin(), m_logicController->forecasts().end(),
                            [](const Forecast &a, const Forecast &b) { return a.name < b.name; });
              } else {
                  std::sort(m_logicController->forecasts().begin(), m_logicController->forecasts().end(),
                            [](const Forecast &a, const Forecast &b) { return a.name > b.name; });
              }
              break;
      
          case Price:
              if (order == Qt::AscendingOrder) {
                  std::sort(m_logicController->forecasts().begin(), m_logicController->forecasts().end(),
                            [](const Forecast &a, const Forecast &b) { return a.price < b.price; });
              } else {
                  std::sort(m_logicController->forecasts().begin(), m_logicController->forecasts().end(),
                            [](const Forecast &a, const Forecast &b) { return a.price > b.price; });
              }
              break;
          }
      }
      

      Is it enough or something more is required?

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

      @CuriousPan
      Well, you certainly do not want to have called sourceModel()->sort() inside ForecastingProxyModel::lessThan(), so that's an improvement!

      You don't call (or show you have called) your ForecastingModel::sort(), so I think that is irrelevant.

      Then your view is attached to your QSortFilterProxyModel. I would start by debugging/printing from within lessThan() to see which column is in the QModelIndexes to compare so you know what it is sorting by, and maybe check the values. I don't think your "Printout of the situation inside the datastructure:" is relevant because you are accessing via the QSortFilterProxyModel, so the ordering comes from there.

      While I think of it: I don't think your lessThan() handles any QVariant types not already catered for in https://doc.qt.io/qt-5/qsortfilterproxymodel.html#lessThan (except maybe Bool, but that probably degenerates correctly anyway, or isn't relevant to your data), so don't think your lessThan() does anything which is actually needed?

      C 1 Reply Last reply
      0
      • JonBJ JonB

        @CuriousPan
        Well, you certainly do not want to have called sourceModel()->sort() inside ForecastingProxyModel::lessThan(), so that's an improvement!

        You don't call (or show you have called) your ForecastingModel::sort(), so I think that is irrelevant.

        Then your view is attached to your QSortFilterProxyModel. I would start by debugging/printing from within lessThan() to see which column is in the QModelIndexes to compare so you know what it is sorting by, and maybe check the values. I don't think your "Printout of the situation inside the datastructure:" is relevant because you are accessing via the QSortFilterProxyModel, so the ordering comes from there.

        While I think of it: I don't think your lessThan() handles any QVariant types not already catered for in https://doc.qt.io/qt-5/qsortfilterproxymodel.html#lessThan (except maybe Bool, but that probably degenerates correctly anyway, or isn't relevant to your data), so don't think your lessThan() does anything which is actually needed?

        C Offline
        C Offline
        CuriousPan
        wrote on last edited by CuriousPan
        #10

        @JonB,
        After suggested debugging I found out following things:

        1. lessThan method considers Date as String, which I find quite suprising. I can fix it by checking the data behind QModelIndex using not QMetaType, but rather column number.
        2. lessThan doesn't recognize bool type too.
        3. lessThan considers columns correctly.

        While I think of it: I don't think your lessThan() handles any QVariant types not already catered for in https://doc.qt.io/qt-5/qsortfilterproxymodel.html#lessThan (except maybe Bool, but that probably degenerates correctly anyway, or isn't relevant to your data), so don't think your lessThan() does anything which is actually needed?

        What do you exactly mean by this?

        You don't call (or show you have called) your ForecastingModel::sort(), so I think that is irrelevant.

        Where am I supposed to call it? Isn't it a slot wihich is called autimatically?

        JonBJ 1 Reply Last reply
        0
        • C CuriousPan

          Okay, here's the code:

          //m_model is a ForecastingProxyModel class inheriting from QAbstractTableModel
          ForecastingProxyModel *proxyModel = new ForecastingProxyModel(this);
          proxyModel->setSourceModel(m_model);
          ui->forecastingTableView->setModel(proxyModel);
          ui->forecastingTableView->setSortingEnabled(true);
          

          Here's the code of the lessThan of the QSortFilterProxyModel:

          bool ForecastingProxyModel::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const
          {
              const QVariant &leftData = sourceModel()->data(sourceLeft);
              const QVariant &rightData = sourceModel()->data(sourceRight);
              //sourceModel()->sort(sourceLeft.column(), sortOrder());  you said it's a bad idea to call it hear.
          
              if (leftData.userType() == QMetaType::QDate) {
                  return leftData.toDate() < rightData.toDate();
              } else if (leftData.userType() == QMetaType::QString) {
                  return leftData.toString() < rightData.toString();
              } else if (leftData.userType() == QMetaType::Double) {
                  return leftData.toDouble()  < rightData.toDouble();
              } else if (leftData.userType() == QMetaType::Bool) {
                  return leftData.toBool() < rightData.toBool();
              }
          
              return QSortFilterProxyModel::lessThan(sourceLeft, sourceRight);
          }
          

          Here's a sort method of the source model:

          void ForecastingModel::sort(int column, Qt::SortOrder order)
          {
              switch(column) {
              case Name:
                  if (order == Qt::AscendingOrder) {
                      std::sort(m_logicController->forecasts().begin(), m_logicController->forecasts().end(),
                                [](const Forecast &a, const Forecast &b) { return a.name < b.name; });
                  } else {
                      std::sort(m_logicController->forecasts().begin(), m_logicController->forecasts().end(),
                                [](const Forecast &a, const Forecast &b) { return a.name > b.name; });
                  }
                  break;
          
              case Price:
                  if (order == Qt::AscendingOrder) {
                      std::sort(m_logicController->forecasts().begin(), m_logicController->forecasts().end(),
                                [](const Forecast &a, const Forecast &b) { return a.price < b.price; });
                  } else {
                      std::sort(m_logicController->forecasts().begin(), m_logicController->forecasts().end(),
                                [](const Forecast &a, const Forecast &b) { return a.price > b.price; });
                  }
                  break;
              }
          }
          

          Is it enough or something more is required?

          Christian EhrlicherC Offline
          Christian EhrlicherC Offline
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on last edited by
          #11

          @CuriousPan said in How to sort original data structure of QAbstractTableModel?:

          bool ForecastingProxyModel::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const
          {
          const QVariant &leftData = sourceModel()->data(sourceLeft);
          const QVariant &rightData = sourceModel()->data(sourceRight);
          //sourceModel()->sort(sourceLeft.column(), sortOrder()); you said it's a bad idea to call it hear.

          if (leftData.userType() == QMetaType::QDate) {
              return leftData.toDate() < rightData.toDate();
          } else if (leftData.userType() == QMetaType::QString) {
              return leftData.toString() < rightData.toString();
          } else if (leftData.userType() == QMetaType::Double) {
              return leftData.toDouble()  < rightData.toDouble();
          } else if (leftData.userType() == QMetaType::Bool) {
              return leftData.toBool() < rightData.toBool();
          }
          
          return QSortFilterProxyModel::lessThan(sourceLeft, sourceRight);
          

          This is not needed. QSortFilterProxyModel does exact the same (and honors more meta types than your implementation)

          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
          Visit the Qt Academy at https://academy.qt.io/catalog

          C 1 Reply Last reply
          1
          • Christian EhrlicherC Christian Ehrlicher

            @CuriousPan said in How to sort original data structure of QAbstractTableModel?:

            bool ForecastingProxyModel::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const
            {
            const QVariant &leftData = sourceModel()->data(sourceLeft);
            const QVariant &rightData = sourceModel()->data(sourceRight);
            //sourceModel()->sort(sourceLeft.column(), sortOrder()); you said it's a bad idea to call it hear.

            if (leftData.userType() == QMetaType::QDate) {
                return leftData.toDate() < rightData.toDate();
            } else if (leftData.userType() == QMetaType::QString) {
                return leftData.toString() < rightData.toString();
            } else if (leftData.userType() == QMetaType::Double) {
                return leftData.toDouble()  < rightData.toDouble();
            } else if (leftData.userType() == QMetaType::Bool) {
                return leftData.toBool() < rightData.toBool();
            }
            
            return QSortFilterProxyModel::lessThan(sourceLeft, sourceRight);
            

            This is not needed. QSortFilterProxyModel does exact the same (and honors more meta types than your implementation)

            C Offline
            C Offline
            CuriousPan
            wrote on last edited by
            #12

            @Christian-Ehrlicher, do you suggest totally removing the method?

            1 Reply Last reply
            0
            • C CuriousPan

              @JonB,
              After suggested debugging I found out following things:

              1. lessThan method considers Date as String, which I find quite suprising. I can fix it by checking the data behind QModelIndex using not QMetaType, but rather column number.
              2. lessThan doesn't recognize bool type too.
              3. lessThan considers columns correctly.

              While I think of it: I don't think your lessThan() handles any QVariant types not already catered for in https://doc.qt.io/qt-5/qsortfilterproxymodel.html#lessThan (except maybe Bool, but that probably degenerates correctly anyway, or isn't relevant to your data), so don't think your lessThan() does anything which is actually needed?

              What do you exactly mean by this?

              You don't call (or show you have called) your ForecastingModel::sort(), so I think that is irrelevant.

              Where am I supposed to call it? Isn't it a slot wihich is called autimatically?

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

              @CuriousPan
              If you followed my link it lists:

              This function is used as the < operator when sorting, and handles the following QVariant types:

              So you see how it says which QVariant types it handles and that includes the ones you handle. It also includes QMetaType::QDate so I don't know why your "lessThan method considers Date as String, which I find quite suprising". I don't believe you need your own override.

              EDIT I can see @Christian-Ehrlicher agrees.

              Put qDebug() statements inside your sort() to see whether it's called. Your view is attached to the QSortFilterProxyModel rather than the underlying model. I'm not sure, but find out which models' sorting are getting used/called. I don't think QSortFilterProxyModel::sort() will call sourceModel->sort(). I think it's confusing to have sorting on your source model and also to be using QSortFilterProxyModel against it.

              Where am I supposed to call it?

              I would normally expect you to sort a (source) model immediately after you populate it if you want it sorted. So wherever that is in your code.

              1 Reply Last reply
              0
              • C Offline
                C Offline
                CuriousPan
                wrote on last edited by CuriousPan
                #14

                After removing lessThan method I have following behavior:

                1. QSortFilterProxyModel::sort() is getting called, but not the source one, hence I have to call source::sort() inside it. It sorts source data, but view isn't changing.
                JonBJ 1 Reply Last reply
                0
                • C CuriousPan

                  After removing lessThan method I have following behavior:

                  1. QSortFilterProxyModel::sort() is getting called, but not the source one, hence I have to call source::sort() inside it. It sorts source data, but view isn't changing.
                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by
                  #15

                  @CuriousPan
                  I have said before: I do not know why you are using a QSortFilterProxyModel and also doing sourceModel()->sort(). If you want to sort the underlying model I don't know why you want the proxy too. But there you are.

                  Meanwhile, since again you do not show your code for "hence I have to call source::sort() inside it", we do not know what you are doing. Are you/do you need to take QSortFilterProxyModel::sortColumn() & QSortFilterProxyModel::sortOrder() into account?

                  It sorts source data, but view isn't changing.

                  I have said before: the view is bound to the QSortFilterProxyModel, not the source model directly, so I don't know that any change you might or might not make in the source model's rows' order would be reflected in either the QSortFilterProxyModel or any view bound to it.

                  I would get it working with either the QSortFilterProxyModel and no source model sort() or source model sort() and no QSortFilterProxyModel --- and possibly compare the two --- before I tried to understand what was happening with both in play.

                  That's all I know to say.

                  1 Reply Last reply
                  1
                  • C Offline
                    C Offline
                    CuriousPan
                    wrote on last edited by
                    #16

                    After searching the internet I guess I found a solution. After sorting the data it's important to emit dataChanged.
                    Thanks everyone who tried to help me.

                    JonBJ 1 Reply Last reply
                    1
                    • C CuriousPan

                      After searching the internet I guess I found a solution. After sorting the data it's important to emit dataChanged.
                      Thanks everyone who tried to help me.

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

                      @CuriousPan
                      That is a good point, which I should have thought about! :)

                      I still don't know why you want both to sort the model and to have a sort proxy on top of it. You sure you want the QSortFilterProxyModel at all, given your desire to sort the underlying model? Best of luck.

                      1 Reply Last reply
                      1
                      • Christian EhrlicherC Offline
                        Christian EhrlicherC Offline
                        Christian Ehrlicher
                        Lifetime Qt Champion
                        wrote on last edited by
                        #18

                        @JonB said in How to sort original data structure of QAbstractTableModel?:

                        I still don't know why you want both to sort the model and to have a sort proxy on top of it.

                        Because he does not understand what a QSortFilterProxyModel is doing...

                        Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                        Visit the Qt Academy at https://academy.qt.io/catalog

                        C 1 Reply Last reply
                        0
                        • Christian EhrlicherC Christian Ehrlicher

                          @JonB said in How to sort original data structure of QAbstractTableModel?:

                          I still don't know why you want both to sort the model and to have a sort proxy on top of it.

                          Because he does not understand what a QSortFilterProxyModel is doing...

                          C Offline
                          C Offline
                          CuriousPan
                          wrote on last edited by
                          #19

                          @Christian-Ehrlicher, yeah, you are right. I was given the example with QSortFilterProxyModel so I thought it's mandatory to use it. I've removed it.

                          1 Reply Last reply
                          1
                          • Christian EhrlicherC Offline
                            Christian EhrlicherC Offline
                            Christian Ehrlicher
                            Lifetime Qt Champion
                            wrote on last edited by Christian Ehrlicher
                            #20

                            Sorting the base model is normally much more expansive than using a QSortFilterProxyModel so it should be avoided.

                            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                            Visit the Qt Academy at https://academy.qt.io/catalog

                            1 Reply Last reply
                            3

                            • Login

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