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. QSortFilterProxyModel is super slow in Qt-5.15.2
Forum Update on Monday, May 27th 2025

QSortFilterProxyModel is super slow in Qt-5.15.2

Scheduled Pinned Locked Moved Solved General and Desktop
modelfilteringqsortfilterprox
4 Posts 2 Posters 459 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.
  • S Offline
    S Offline
    Sivan
    wrote on 22 Oct 2024, 01:54 last edited by Sivan
    #1

    Hi all,

    I am currently using Qt-5.15.2 on MacOS 14.5 (MacBook Pro M1) and creating a feature that uses QSortFilterProxyModel. This feature is part of an existing complex application and upgrading to Qt 6 is not a choice at the moment. I noticed that whenever I tried to filter items, the process was extremely slow.

    Here is my test case. I used customsortFilterModel example in Qt and simplified it.

    • The original model is a simple model inherited from QAbstractItemModel.
    • In this model, the rowCount is 25000 while columnCount is only 3.
    • Removed the proxy view (QTreeView) from the example as it was very slow to even launch the app.
    • Connected a button to do the filtering on proxyModel (QSortFilterProxyModel). In the slot of the button click, I called invalidateFilter() on the proxyModel.
    • Override filterAcceptRow function to return true/false for even/odd rows respectively.
    SourceModel::SourceModel(QObject* p_Parent)
        : QAbstractItemModel(p_Parent)
    {
    }
    
    SourceModel::~SourceModel()
    {
    }
    
    QVariant SourceModel::headerData(int p_Section, Qt::Orientation p_Orientation, int p_Role) const
    {
        if (p_Role != Qt::DisplayRole) return QVariant();
    
        switch (p_Section)
        {
            case 1: return QVariant("Column 1");
            case 2: return QVariant("Column 2");
            default:
                return QVariant("Column 3");
        }
    }
    
    QVariant SourceModel::data(const QModelIndex& p_Index, int p_Role) const
    {
        if (p_Role != Qt::DisplayRole) return QVariant();
    
        switch (p_Index.column())
        {
            case 1: return QVariant(p_Index.row() + 1);
            case 2: return QVariant(QString("Column 2 Row %1").arg(p_Index.row() + 1));
            default:
                return QVariant(QString("Last Column Row %1").arg(p_Index.row() + 1));
        }
    }
    
    int SourceModel::rowCount(const QModelIndex& p_Parent) const
    {
        return 25000;
    }
    
    int SourceModel::columnCount(const QModelIndex& p_Parent) const
    {
        return 3;
    }
    
    QModelIndex SourceModel::index(int p_Row, int p_Column, const QModelIndex& p_Parent) const
    {
        return createIndex(p_Row, p_Column);
    }
    
    MySortFilterProxyModel::MySortFilterProxyModel(QObject *parent)
        : QSortFilterProxyModel(parent)
    {
    }
    
    void MySortFilterProxyModel::SetIsFilterRows(bool p_IsFilter)
    {
        isFilter = p_IsFilter;
        invalidateRowsFilter(); // invalidateFilter();
    }
    
    bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow,
            const QModelIndex &sourceParent) const
    {
        if (!isFilter) return true;
    
        return (sourceRow & 1);
    }
    
    Window::Window()
    {
         proxyModel = new MySortFilterProxyModel(this);
         sourceView = new QTreeView;
    
        .... // Other UI inits
    
        QPushButton* btn = new QPushButton("Filter Items", this);
        btn->setCheckable(true);
        connect(btn, &QPushButton::toggled, proxyModel, &MySortFilterProxyModel::SetIsFilterRows);
    
        ... // Add to layouts
    }
    
    void Window::setSourceModel(QAbstractItemModel *model)
    {
        proxyModel->setSourceModel(model);
        sourceView->setModel(model);
    }
    
    void Window::showEvent(QShowEvent* p_Event)
    {
        const QModelIndex& index = proxyModel->mapToSource(proxyModel->index(0, 0)); // To force the proxy model to create mapping since there is no proxy view now. 
        QWidget::showEvent(p_Event);
    }
    

    Observations - Whenever the model is filtering data, it's extremely slow. It takes about 5 seconds plus. It is not even because of the view since I removed the proxy view. I have attached screenshot from time profile

    Screenshot 2024-10-21 at 12.58.54 PM.png Screenshot 2024-10-21 at 12.58.43 PM.png

    I backported the following fixes, and used invalidateRowsFilter() instead
    https://github.com/qt/qtbase/commit/8455bfee76ed3f1bd3bba8bd3688a7afa94ae0bb
    https://github.com/qt/qtbase/commit/b5f6a85d274

    It improved the performance from 5 seconds to 3 seconds plus. But I still find it slow. Finally, I tried it with Qt6. And that improved the performance tremendously (~200ms). However, I am not able to find any other commits that would contribute to this performance improvement. I am suspecting the replacement of QVector to QList, but I am not sure.

    Could any expert here please advise on what contributes to the performance improvement in Qt6. Thanks in advance.

    1 Reply Last reply
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 22 Oct 2024, 13:32 last edited by
      #2

      Hi,

      I see a lot of call to detach which seems odd for just showing data.
      Can you share your model implementation ?

      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 22 Oct 2024, 15:14
      0
      • S SGaist
        22 Oct 2024, 13:32

        Hi,

        I see a lot of call to detach which seems odd for just showing data.
        Can you share your model implementation ?

        S Offline
        S Offline
        Sivan
        wrote on 22 Oct 2024, 15:14 last edited by
        #3

        Hi @SGaist , both the source and proxy model code are attached above. I just did not include header files.

        1 Reply Last reply
        0
        • S Offline
          S Offline
          Sivan
          wrote on 25 Oct 2024, 02:00 last edited by
          #4

          I was able to fix this with the following:
          https://github.com/qt/qtbase/commit/7d92ef63d7c

          And the following patch in Qt-5.15.2 which tremendously improved the timing:

          Screenshot 2024-10-25 at 9.59.59 AM.png

          1 Reply Last reply
          2
          • S Sivan has marked this topic as solved on 25 Oct 2024, 02:01

          2/4

          22 Oct 2024, 13:32

          • Login

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