Subclass QSortFilterProxyModel to filter multiple values on same column - Is it possible?
-
Hey,
I would like to know if I can filter several different ID's in one column with a QSortFilterProxyModel?
I imagined the whole thing so that I build a function that is called e.g. setIdFilters(const QList<int> ids) and filterAcceptRows filters out the corresponding ones.
Unfortunately I didn't find anything, only that I can filter several columns at the same time or only one value from a column.
I'm mainly interested in is this technically feasible or will it not work?
Thanks for tipps
-
@Gabber
In a word, if you override filterAcceptsRow() you can write whatever logic you want there to determine whether to returntrue
orfalse
, given that it passesint source_row
as parameter for you to look at.The default implementation returns true if the value held by the relevant item matches the filter string, wildcard string or regular expression.
So the other "filter" methods are just "defaults" you can specify if you don't want to override this method. If you do, it's up to your code what you do or look at. Your use case of "look up id column value in row in a list of wanted ids" is perfectly doable.
Note btw that
filterAcceptRow()
returningtrue
filters in the corresponding row, rather than filtering it out.@JonB
Can you maybe help me again for a moment?class GermanNameFilterModel : public QSortFilterProxyModel { Q_OBJECT public: explicit GermanNameFilterModel(QObject *parent = nullptr); ~GermanNameFilterModel(); void setIdFilterList(const QList<int> idFilterList); bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; private: const int mIdColumn = 0; QList<int> mIdFilterList; };
GermanNameFilterModel::GermanNameFilterModel(QObject *parent) : QSortFilterProxyModel{parent}{} GermanNameFilterModel::~GermanNameFilterModel(){} void GermanNameFilterModel::setIdFilterList(const QList<int> idFilterList) { if(mIdFilterList != idFilterList) { mIdFilterList = idFilterList; emit invalidateFilter(); } } bool GermanNameFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { if(mIdFilterList.size() == 1) { QModelIndex index = sourceModel()->index(source_row, mIdColumn, source_parent); int id = sourceModel()->data(index).toInt(); if(mIdFilterList.at(0) == id) return true; return false; } else { QModelIndex index = sourceModel()->index(source_row, mIdColumn, source_parent); int id = sourceModel()->data(index).toInt(); for(int i=0; i<mIdFilterList.size(); i++){ if(mIdFilterList.at(i) == id) return true; } return false; } }
This code works as long as
mIdFilterList.size() == 1
. IfmIdFilterList.size()
is greater than 1, then my program freezes and is completely black.So I started the debugger and saw what happens when the list is greater than 1. After the return true it calls invalidateFilter() from the function setIdFilterList().
Unfortunately I don't have the knowledge now. Assuming my list (mIdFilterList) contains two elements then filterAcceptsRow should return true at least twice or? According to the debugger it does that but in between it always calls invalidateFilter().
Can you please give me some help?
Thanks!
-
Hey,
I would like to know if I can filter several different ID's in one column with a QSortFilterProxyModel?
I imagined the whole thing so that I build a function that is called e.g. setIdFilters(const QList<int> ids) and filterAcceptRows filters out the corresponding ones.
Unfortunately I didn't find anything, only that I can filter several columns at the same time or only one value from a column.
I'm mainly interested in is this technically feasible or will it not work?
Thanks for tipps
@Gabber
In a word, if you override filterAcceptsRow() you can write whatever logic you want there to determine whether to returntrue
orfalse
, given that it passesint source_row
as parameter for you to look at.The default implementation returns true if the value held by the relevant item matches the filter string, wildcard string or regular expression.
So the other "filter" methods are just "defaults" you can specify if you don't want to override this method. If you do, it's up to your code what you do or look at. Your use case of "look up id column value in row in a list of wanted ids" is perfectly doable.
Note btw that
filterAcceptRow()
returningtrue
filters in the corresponding row, rather than filtering it out. -
@Gabber
In a word, if you override filterAcceptsRow() you can write whatever logic you want there to determine whether to returntrue
orfalse
, given that it passesint source_row
as parameter for you to look at.The default implementation returns true if the value held by the relevant item matches the filter string, wildcard string or regular expression.
So the other "filter" methods are just "defaults" you can specify if you don't want to override this method. If you do, it's up to your code what you do or look at. Your use case of "look up id column value in row in a list of wanted ids" is perfectly doable.
Note btw that
filterAcceptRow()
returningtrue
filters in the corresponding row, rather than filtering it out.@JonB
Thank you for your reply. In that case I will try to implement it. -
@Gabber
In a word, if you override filterAcceptsRow() you can write whatever logic you want there to determine whether to returntrue
orfalse
, given that it passesint source_row
as parameter for you to look at.The default implementation returns true if the value held by the relevant item matches the filter string, wildcard string or regular expression.
So the other "filter" methods are just "defaults" you can specify if you don't want to override this method. If you do, it's up to your code what you do or look at. Your use case of "look up id column value in row in a list of wanted ids" is perfectly doable.
Note btw that
filterAcceptRow()
returningtrue
filters in the corresponding row, rather than filtering it out.@JonB
Can you maybe help me again for a moment?class GermanNameFilterModel : public QSortFilterProxyModel { Q_OBJECT public: explicit GermanNameFilterModel(QObject *parent = nullptr); ~GermanNameFilterModel(); void setIdFilterList(const QList<int> idFilterList); bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; private: const int mIdColumn = 0; QList<int> mIdFilterList; };
GermanNameFilterModel::GermanNameFilterModel(QObject *parent) : QSortFilterProxyModel{parent}{} GermanNameFilterModel::~GermanNameFilterModel(){} void GermanNameFilterModel::setIdFilterList(const QList<int> idFilterList) { if(mIdFilterList != idFilterList) { mIdFilterList = idFilterList; emit invalidateFilter(); } } bool GermanNameFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { if(mIdFilterList.size() == 1) { QModelIndex index = sourceModel()->index(source_row, mIdColumn, source_parent); int id = sourceModel()->data(index).toInt(); if(mIdFilterList.at(0) == id) return true; return false; } else { QModelIndex index = sourceModel()->index(source_row, mIdColumn, source_parent); int id = sourceModel()->data(index).toInt(); for(int i=0; i<mIdFilterList.size(); i++){ if(mIdFilterList.at(i) == id) return true; } return false; } }
This code works as long as
mIdFilterList.size() == 1
. IfmIdFilterList.size()
is greater than 1, then my program freezes and is completely black.So I started the debugger and saw what happens when the list is greater than 1. After the return true it calls invalidateFilter() from the function setIdFilterList().
Unfortunately I don't have the knowledge now. Assuming my list (mIdFilterList) contains two elements then filterAcceptsRow should return true at least twice or? According to the debugger it does that but in between it always calls invalidateFilter().
Can you please give me some help?
Thanks!
-
@JonB
Can you maybe help me again for a moment?class GermanNameFilterModel : public QSortFilterProxyModel { Q_OBJECT public: explicit GermanNameFilterModel(QObject *parent = nullptr); ~GermanNameFilterModel(); void setIdFilterList(const QList<int> idFilterList); bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; private: const int mIdColumn = 0; QList<int> mIdFilterList; };
GermanNameFilterModel::GermanNameFilterModel(QObject *parent) : QSortFilterProxyModel{parent}{} GermanNameFilterModel::~GermanNameFilterModel(){} void GermanNameFilterModel::setIdFilterList(const QList<int> idFilterList) { if(mIdFilterList != idFilterList) { mIdFilterList = idFilterList; emit invalidateFilter(); } } bool GermanNameFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { if(mIdFilterList.size() == 1) { QModelIndex index = sourceModel()->index(source_row, mIdColumn, source_parent); int id = sourceModel()->data(index).toInt(); if(mIdFilterList.at(0) == id) return true; return false; } else { QModelIndex index = sourceModel()->index(source_row, mIdColumn, source_parent); int id = sourceModel()->data(index).toInt(); for(int i=0; i<mIdFilterList.size(); i++){ if(mIdFilterList.at(i) == id) return true; } return false; } }
This code works as long as
mIdFilterList.size() == 1
. IfmIdFilterList.size()
is greater than 1, then my program freezes and is completely black.So I started the debugger and saw what happens when the list is greater than 1. After the return true it calls invalidateFilter() from the function setIdFilterList().
Unfortunately I don't have the knowledge now. Assuming my list (mIdFilterList) contains two elements then filterAcceptsRow should return true at least twice or? According to the debugger it does that but in between it always calls invalidateFilter().
Can you please give me some help?
Thanks!
@Gabber said in Subclass QSortFilterProxyModel to filter multiple values on same column - Is it possible?:
If mIdFilterList.size() is greater than 1, then my program freezes and is completely black.
I can no reason why this should be the case, your code looks good. BTW for a
QList<int>
you should just be able to use:return mIdFilterList.contains(id);
to avoid your loop in the second case, and works for first case too.
After the return true it calls invalidateFilter() from the function setIdFilterList().
And when is your
setIdFilterList()
called, because your code does not show that? The QSFPM callingfilterAcceptsRow()
to determine what rows to include should not have any reason to be updating any filter list? IfsetIdFilterList()
/emit invalidateFilter();
is called during filtering I can believe that might re-start filtration evaluation, and thus lead to "freezing"? -
@Gabber said in Subclass QSortFilterProxyModel to filter multiple values on same column - Is it possible?:
If mIdFilterList.size() is greater than 1, then my program freezes and is completely black.
I can no reason why this should be the case, your code looks good. BTW for a
QList<int>
you should just be able to use:return mIdFilterList.contains(id);
to avoid your loop in the second case, and works for first case too.
After the return true it calls invalidateFilter() from the function setIdFilterList().
And when is your
setIdFilterList()
called, because your code does not show that? The QSFPM callingfilterAcceptsRow()
to determine what rows to include should not have any reason to be updating any filter list? IfsetIdFilterList()
/emit invalidateFilter();
is called during filtering I can believe that might re-start filtration evaluation, and thus lead to "freezing"?@JonB said in Subclass QSortFilterProxyModel to filter multiple values on same column - Is it possible?:
return mIdFilterList.contains(id);
Thanks, for that tip!
@JonB said in Subclass QSortFilterProxyModel to filter multiple values on same column - Is it possible?:
And when is your setIdFilterList() called, because your code does not show that?
That was the mistake. I had called setIdFilterList, but then did not continue working with the QSFPM but with the source model.
The code works fine!
Slowly I come also already completely confused with the whole German names code Laugh.
Thanks again for your tip!