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

Table model , header data is getting sorted



  • Hi guys

    I am working on a Table and I want to implement sort functionality.
    I have implemented sorting but table's header is also getting sorted with my data. How can I avoid my header getting sorted along with data?

    code:

    tablemodel.h
    
    #ifndef TABLEMODEL_H
    #define TABLEMODEL_H
    #include <QDebug>
    #include <QObject>
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QAbstractTableModel>
    #include <QThread>
    #include <copydata.h>
    #include <QtCore/qsortfilterproxymodel.h>
    #include <QtQml/qjsvalue.h>
    #include <QSortFilterProxyModel>
    class TableModel :  public QAbstractTableModel
    {
        Q_OBJECT
    public:
            explicit TableModel(QObject *parent = nullptr);
    
            int rowCount(const QModelIndex & = QModelIndex()) const override;
    
            int columnCount(const QModelIndex & = QModelIndex()) const override;
    
            QVariant data(const QModelIndex &index, int role) const override;
    
            QHash<int, QByteArray> roleNames() const override;
    
            Q_INVOKABLE void updateTable(QString firstName,QString lastName,QString age);
            Q_INVOKABLE void createCopyThread();
            void addInitialData();
            static TableModel *getStaticInstance();
            QSortFilterProxyModel *getProxyModelInstance();
            enum  TableContentRole {
                TableDataRole = Qt::UserRole + 1,
                HeaderRole
            };
           Q_INVOKABLE void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
    
    private:
    
    signals:void countChanged();
    
    public slots:
    public: QString name;
            QString last_name;
            QString age_x;
    private :
            QVector<QVector<QString>>table;
            static TableModel   *m_staticInstance;
            QSortFilterProxyModel *proxyModel;
    };
    
    #endif // TABLEMODEL_H
    

    tablemodel.cpp

    #include "tablemodel.h"
    
    TableModel *TableModel::m_staticInstance = nullptr;
    
    TableModel::TableModel(QObject *parent) :QAbstractTableModel (parent)
    {
    //    m_staticInstance = new TableModel();
    }
    
    int TableModel::rowCount(const QModelIndex &) const
    {
        return table.size();
    }
    
    int TableModel::columnCount(const QModelIndex &) const
    {
        return table.at(0).size();
    }
    
    QVariant TableModel::data(const QModelIndex &index, int role) const
    { if (role != TableDataRole && role != HeaderRole)
            return QVariant();
    
        if(role == TableDataRole) {
            return table.at(index.row()).at(index.column());
        }
        else if(role == HeaderRole) {
            if(index.row() == 0)
                return true;
            else
                return false;
        }
    
        qDebug()<<"count";
    
        return QVariant();
    }
    
    
    QHash<int, QByteArray> TableModel::roleNames() const
    {
        QHash<int, QByteArray> roles;
        roles[TableDataRole] = "tableData";
        roles[HeaderRole] = "headerData";
        return roles;
    }
    
    void TableModel::updateTable(QString firstName, QString lastName, QString age)
    {
        name = firstName;
        last_name = lastName;
        age_x = age;
        qDebug()<<"FIRSTNAME IS "<<name<<"\n"<<"LASTNAME IS"<<last_name<<"\n"<<"AGE IS "<<age_x<<"\n";
        qDebug()<<"INDEX : "<<table.size();
       // table.append({name,last_name,age_x});
         QModelIndex indexPos=index(5,0);
         QModelIndex indexPosLast=index(5,2);
         qDebug() << "TableModel:" << table;
       //  emit dataChanged(indexPos,indexPosLast);
    
    
    
    
    
         beginInsertRows(QModelIndex(), table.size(),table.size());
    
         table.append({name,last_name,age_x});
         endInsertRows();
    
    
    
    }
    
    void TableModel::createCopyThread()
    {
        QThread *workerthread = new QThread();
        CopyData *worker = new CopyData(table);
        worker->moveToThread(workerthread);
    
        //STARTED
        QObject::connect(workerthread,SIGNAL(started()),worker,SLOT(copyTable()));
        QObject::connect(worker,SIGNAL(workFinished()),workerthread,SLOT(quit()));
        QObject::connect(workerthread,SIGNAL(finished()),worker,SLOT(deleteLater()));
        QObject::connect(workerthread,SIGNAL(finished()),workerthread,SLOT(deleteLater()));
        //FINISHED
        workerthread->start();
    }
    
    void TableModel::addInitialData()
    {
        table.append({"TIME","TYPE","MESSAGE"});
        table.append({"31-Oct-2018 11:34","Event","Service mode"});
        table.append({"8-Oct-2018 12:30","Event","System On"});
        table.append({"6-Oct-2018 12:40","Alarm","Ppeak low inactive"});
        table.append({"20-Oct-2018 13:50","Alarm","Apnea inactive"});
        table.append({"22-Oct-2018 11:34","Event","Service mode"});
        table.append({"3-Oct-2018 12:30","Event","System On"});
        table.append({"4-Oct-2018 12:40","Alarm","Ppeak low inactive"});
        table.append({"1-Oct-2018 13:50","Alarm","Apnea inactive"});
        table.append({"31-Oct-2018 17:34","Event","Service mode"});
        table.append({"31-Oct-2018 18:30","Event","System On"});
        table.append({"31-Oct-2018 12:40","Alarm","Ppeak low inactive"});
        table.append({"31-Oct-2018 13:50","Alarm","Apnea inactive"});
    }
    
    TableModel *TableModel::getStaticInstance()
    {
            if(m_staticInstance == nullptr)
            m_staticInstance = new TableModel();
            return m_staticInstance;
    }
    
    QSortFilterProxyModel *TableModel::getProxyModelInstance()
    {
        proxyModel = new QSortFilterProxyModel();
        return proxyModel;
    }
    
    void TableModel::sort(int column, Qt::SortOrder order)
    {
              proxyModel->sort(0,Qt::AscendingOrder);  //hard coded just for testing 
               qDebug("Sorting by column %d", column);
    
    }
    

    defined in main.cpp

    TableModel *t1 = TableModel::getStaticInstance();//Model
         QSortFilterProxyModel  *proxyModel =t1 ->getProxyModelInstance();
         proxyModel->setSourceModel(t1);
         proxyModel->setSortRole(TableModel::TableDataRole);
    

    I am calling sort() function from qml.

    MouseArea
            {
                anchors.fill:parent
                onClicked:
                {
                tableModelController.sort(0,Qt.AscendingOrder)
    
                }
            }
    
        
    

    Before sort Result:0_1562155604812_Beforesort.PNG

    after sort result:

    0_1562155634627_aftersort.PNG

    
    So how can I fix header to first row only?

  • Qt Champions 2019

    Simply reimplement headerData() instead returning the header data in data() - data() is only there to return the content, not the header data.



  • Hi @Christian-Ehrlicher

    Thanks for help!!

    I have implemented headerData like this:

    QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
    
             qDebug()<<"header called";
            if (orientation == Qt::Horizontal && role == HeaderRole) {
                if (section == 0) {
                    return tr("TIME");
                } else if (section == 1) {
                    return tr("EVENT");
                }
                else if(section == 2)
                {
                     return tr("MESSAGE");
    
                }
            }
            return QVariant();
    }
    
    
    QVariant TableModel::data(const QModelIndex &index, int role) const
    { if (role != TableDataRole && role != HeaderRole)
            return QVariant();
    
        if(role == TableDataRole) {
            return table.at(index.row()).at(index.column());
        }
      //  else if(role == HeaderRole) {
      //      if(index.row() == 0)
           //     return true;
        //    else
           //     return false;
        //}
    
    
        qDebug()<<"count";
    
        return QVariant();
    }
    

    but I am unable to get header data.
    Do I have to call this function?


  • Qt Champions 2019

    You have to return something for Qt::DisplayRole: https://doc.qt.io/qt-5/qt.html#ItemDataRole-enum



  • hi @Christian-Ehrlicher

    I didn't got what I have to return.

    when I went through the documentation (table ) it was showing Qt::DisplayRole 0.



  • @ashajg
    When a Qt view such as QTableView wants to display what's in your table model, it calls data() and headerData() with role == Qt::DisplayRole. I don't really see where your data() is handling that, but you seem to be saying the data is coming out OK but not the header. For headerData() at least you need to ditch HeaderRole and have something more like:

    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
        return ...
    


  • Hi @JonB

    Thanks for help!!! I ll remove headerData role and assign Display role so that these functions will work.



  • Hi @Christian-Ehrlicher @JonB

    one more question for the same code as sorting I am able to do. Now I want that sorted table should revert back to its previous order on a button click so is there any functionality that QT provides so that I can use it to revert my table back to original order.



  • @ashajg
    You are doing your sorting via QSortFilterProxyModel. Does https://doc.qt.io/qt-5/qsortfilterproxymodel.html#invalidate do what you want ("cancel" the sorting), or does it just cause it to re-sort? [But see https://stackoverflow.com/a/28107562, including the comment there.] If it's the latter it may be that you have to sort when using a QSortFilterProxyModel. In that case read https://stackoverflow.com/questions/18637727/restore-original-order-in-qtableview-qsortfilterproxy for various possibilities.

    P.S.
    Your code has:

    #include <QtCore/qsortfilterproxymodel.h>
    #include <QSortFilterProxyModel>
    

    I don't do Qt C++, but do you really need the first of those two includes? Looks odd to me.



  • @JonB I am using sort function from QSortFilterProxyModel



  • @ashajg

    I am using sort function from QSortFilterProxyModel

    I assume that relates to why you are including <QtCore/qsortfilterproxymodel.h>(?). But if it's not exposed from <QSortFilterProxyModel>(?) then maybe you're not supposed to use it that way? Anyway, as I said, I leave it to you.

    The important stuff to your situation is in my first paragraph.


Log in to reply