How to implement setHeaderData in a subclass of QAbstractTableModel?
-
@jdent
Your code usessetHeaderData()
to explicitly set some header.
From that method you need to save/store that value. Somewhere in your subclass.
Then yourheader()
method needs to retrieve that and return it.
This is what a model like, say,QStandardItemModel
will do for you.
When you use your ownQAbstractTableModel
you have to implement this. In your own member variable structure. For all roles you wish to allow the caller to store data in header.
If you do not need to allow callers to set the header data, e.g. you can calculate what you want, then you don't need asetHeaderData()
or storage, you can just writeheader()
to compute and return values.
It's the same principle as what you do withsetData()
anddata()
in your subclassedQAbstractTableModel
, only done separately for the header data. -
@jdent said in How to implement setHeaderData in a subclass of QAbstractTableModel?:
QAbstractTableModel has no header() method nor its superclass!!
It's a typo - it's headerData() as you already found out...
-
@jdent
Start by correcting your code, your last 2return
statements are not acceptable for any role.if (orientation == Qt::Horizontal) { if (role == Qt::DisplayRole) return QVariant{ tr("Num %1").arg(section) }; return QVariant(); } return QVariant();
Then confirm with a breakpoint/debug statement that your
headerData()
is getting called, and report back.I assume you have a
QHeaderView
in yourQTableView
to see the headers? -
But now I cannot sort by column!!
and I haveVectorModel* model = new VectorModel{ std::unique_ptr<AbstractCollection>(new PersistentCollection{ storage(), select(columns(&Claim::id, &Claim::amount))})}; QSortFilterProxyModel* proxy = new QSortFilterProxyModel{ this }; proxy->setSourceModel(model); ui.tableView->setModel(proxy); ui.tableView->setHorizontalHeader(new QHeaderView{ Qt::Horizontal }); ui.tableView->setSortingEnabled(true); ui.tableView->setSelectionMode(QAbstractItemView::SingleSelection);
-
Anyway I needed to modify sorting: how do I take control of it? For instance if the column has text then alphanumerical sorting must be done and if it is numeric, then the text in the cell must be converted to numeric and the order set numerically! How is this done?
-
@jdent
You should use a QSortFilterProxyModel for displaying your model sorted.treeView = new QTreeView; model = new YourModel; proxyModel = new QSortFilterProxyModel(this); proxyModel->setSourceModel(model); treeview->setModel(proxyModel);
Then you do sorting (and optionally filtering too) in the proxy model code.
-
@jdent
If you go to the doc page I referenced and read through you will find it describes exactly what you need to do and how it relates toQSortFilterProxyModel
or sorting your model.The idea is to read through the documentation, search for examples and ask questions here when you have researched and have a problem.
-
Ok, I implemented a subclass of QSortFilterProxyModel in the following :
class SortFilterProxyModel : public QSortFilterProxyModel { Q_OBJECT public: SortFilterProxyModel(QObject* parent = nullptr) : QSortFilterProxyModel(parent) {} bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const override { QVariant left_data = sourceModel()->data(source_left); QVariant right_data = sourceModel()->data(source_right); switch (left_data.userType()) { case QMetaType::QDateTime: return left_data.toDateTime() < right_data.toDateTime(); case QMetaType::Int: return left_data.toInt() < right_data.toInt(); case QMetaType::QString: return left_data.toString() < right_data.toString(); default: return QSortFilterProxyModel::lessThan(source_left, source_right); } } };
HOWEVER, I click on the header view and nothing happens!! Why?
This is with the subclass and without it!! I would expect resorting to occur in the reverse order when clicking the header but nothing changes! -
@jdent
Did you look at the docs page? Did you follow the Sorting section code?Although it does no harm, with what is in your
lessThan()
at present I don't think you needed to override it. QSortFilterProxyModel::lessThan() already handles the types you have coded for. But if you were to change the behaviour that's where you would do it. -
Again, sorting is ok - and you are right not needed to subclass it... The problem I am having is that the QHeaderView does not respond to clicking the mouse!! So, I cannot change the column used to sort at runtime!!
Yet I have:
ui.tableView->setHorizontalHeader(new QHeaderView{ Qt::Horizontal }); ui.tableView->setSortingEnabled(true);
And yes I read the Sorting section code!
-
At runtime, sort() and lessThan() get called at the beginning (when below code executes) but not when I click the header... also the column's sort indicator is not responding to my clicks and sorting is not happening when I click the header only after the following code executes
When this code executes, sort() is called once and lessThan() is called many times (proportional to number of rows):
ui.tableView->setSortingEnabled(true);
but not anymore afterwards !
-
@jdent said in How to implement setHeaderData in a subclass of QAbstractTableModel?:
but not anymore afterwards !
Why should it - once it's sorted why would it need to sort it again?
Please provide a minimal, compilable example of your problem.
-
@jdent said in How to implement setHeaderData in a subclass of QAbstractTableModel?:
but not anymore afterwards !
Not "anymore afterwards" when you do what?
The behaviour I would expect is:
-
The first time you click on a column it should do a sort on that column. You should then see the "sort indicator" on that column's header being shown pointing up or down, to indicate it is sorted on that column in a certain direction.
-
If you click on that column again it should reverse sort, and the indicator should reverse its direction. I am not sure whether it actually issues a
sort()
in this case, since it already has it sorted it could just reverse the order or all the rows showing in the view. Or it may re-sort()
in the opposite direction. -
If you click on a different column it should
sort()
on that new column, and move the sort indicator to show on the new column.
-