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:
after sort result:
So how can I fix header to first row only?
-
Simply reimplement headerData() instead returning the header data in data() - data() is only there to return the content, not the header data.
-
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? -
You have to return something for Qt::DisplayRole: https://doc.qt.io/qt-5/qt.html#ItemDataRole-enum
-
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 asQTableView
wants to display what's in your table model, it callsdata()
andheaderData()
withrole == Qt::DisplayRole
. I don't really see where yourdata()
is handling that, but you seem to be saying the data is coming out OK but not the header. ForheaderData()
at least you need to ditchHeaderRole
and have something more like:if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { return ...
-
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 viaQSortFilterProxyModel
. 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 aQSortFilterProxyModel
. 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.
-
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.