QSortFilterProxyModel returns an artificial string

I am using QSortFilterProxyModel to filter the results from QAbstractListModel. Nevertheless, I would like to return the first record, which is not in the original model, that is, it is somehow artificial.

This is what I have so far:

class ActivedAccountModel(QSortFilterProxyModel): def __init__(self, model, parent=None): super(ActiveAccountModel, self).__init__(parent) self.setSourceModel(model) self.setDynamicSortFilter(True) def data(self, index, role=Qt.DisplayRole): account_info = super(ActiveAccountModel, self).data(index, Qt.UserRole).toPyObject() if role == Qt.DisplayRole: return account_info.name elif role == Qt.UserRole: return account_info return None def filterAcceptsRow(self, source_row, source_parent): source_model = self.sourceModel() source_index = source_model.index(source_row, 0, source_parent) account_info = source_model.data(source_index, Qt.UserRole) return isinstance(account_info.account, Account) and account_info.account.enabled 

This will return the list as:

 Account 1 Account 2 ... 

Id 'would like to return an additional element at the beginning of the returned list of elements f:

 Extra Element Account 1 Account 2 ... 

I tried to override rowCount to return the real rowCount () + 1, but somehow I would need to move all the elements to return this artificial element to index 0, and I got a little lost there.

Any clue? So far I have not been able to find any sample code ... Thanks!

+4
source share
3 answers

I did this only at work, so I cannot give you a lot of code. I can give you a general idea of ​​what to do.

It works better if you are a subclass of QAbstractProxyModel , which is for general manipulation, not for sorting or filtering. You want to override rowCount as well as override columnCount (although this should just return information from the original model). You need to override the data function and return your own data for the first row or call the original model again.

You want to override the mapFromSource and mapToSource functions to allow switching between the proxy model indices and the source model indices.

In order to perform a reliable implementation, you will need to create several slots and connect to the signals of the original model to modify the data, the reset model, and the rows / columns that need to be inserted / deleted. Then you must emit your own signals, adapting them correctly to account for the extra line.

In our class, we prepared the text for the first line, so we can use the same proxy model in different situations. This is worth exploring for you, as it adds minimal effort.

Edit

In the commented request, a rough look at mapToSource and mapFromSource. This is about what you need to think about.

 // Remember that this maps from the proxy index to the source index, // which is invalid for the extra row the proxy adds. mapToSource( proxy_index ): if proxy_index isn't valid: return invalid QModelIndex else if proxy_index is for the first row: return invalid QModelIndex else return source model index for (proxy_index.row - 1, proxy_index.column) mapFromSource( source_index ): if source_index isn't valid: return invalid QModelIndex else if source_index has a parent: // This would occur if you are adding an extra top-level // row onto a tree model. // You would need to decide how to handle that condition return invalid QModelIndex else return proxy model index for (source_index.row + 1, source_index.column) 
+1
source

Because I worked a little with the implementation of this and because I could not find any other example code on the entire network, I publish this implementation of the example.

I hope this helps other people too ...

 /** ** Written by Sven Anders (ANDURAS AG). Public domain code. **/ #include <QDebug> #include <QBrush> #include <QFont> #include <QSortFilterProxyModel> /** Definition **/ class ProxyModelNoneEntry : public QSortFilterProxyModel { Q_OBJECT public: ProxyModelNoneEntry(QString _entry_text = tr("(None)"), QObject *parent=0); int rowCount(const QModelIndex &parent = QModelIndex()) const; /* lessThan() is not necessary for this model to work, but can be implemented in a derived class if a custom sorting method is required. */ // bool lessThan(const QModelIndex &left, const QModelIndex &right) const; QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; QModelIndex mapToSource(const QModelIndex &proxyIndex) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; Qt::ItemFlags flags(const QModelIndex &index) const; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &child) const; private: QString entry_text; }; /** Implementation **/ ProxyModelNoneEntry::ProxyModelNoneEntry(QString _entry_text, QObject *parent) : QSortFilterProxyModel(parent) { entry_text = _entry_text; } int ProxyModelNoneEntry::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return QSortFilterProxyModel::rowCount()+1; } QModelIndex ProxyModelNoneEntry::mapFromSource(const QModelIndex &sourceIndex) const { if (!sourceIndex.isValid()) return QModelIndex(); else if (sourceIndex.parent().isValid()) return QModelIndex(); return createIndex(sourceIndex.row()+1, sourceIndex.column()); } QModelIndex ProxyModelNoneEntry::mapToSource(const QModelIndex &proxyIndex) const { if (!proxyIndex.isValid()) return QModelIndex(); else if (proxyIndex.row() == 0) return QModelIndex(); return sourceModel()->index(proxyIndex.row()-1, proxyIndex.column()); } QVariant ProxyModelNoneEntry::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() == 0) { if (role == Qt::DisplayRole) return entry_text; else if (role == Qt::DecorationRole) return QVariant(); else if (role == Qt::FontRole) { QFont font; font.setItalic(true); return font; } else return QVariant(); } return QSortFilterProxyModel::data(createIndex(index.row(),index.column()), role); } Qt::ItemFlags ProxyModelNoneEntry::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; if (index.row() == 0) return Qt::ItemIsSelectable | Qt::ItemIsEnabled; return QSortFilterProxyModel::flags(createIndex(index.row(),index.column())); } QModelIndex ProxyModelNoneEntry::index(int row, int column, const QModelIndex &parent) const { if (row > rowCount()) return QModelIndex(); return createIndex(row, column); } QModelIndex ProxyModelNoneEntry::parent(const QModelIndex &child) const { Q_UNUSED(child) return QModelIndex(); } 

Relations Sven

+2
source

I have had the same issue recently, and I have many problems with my parents and using the original model.

My version should handle virtual columns on the left, a few related to the actions, and possibly one that is a checkbox.

Hope this helps someone too :)

However, a note to the wise, I will subclass QSortFilterProxyModel, and by doing this I seem to lose the ability to use sorting. I suppose because I override the index / data methods. If earlier I came to a subclass of QIdentityProxyModel and then added QSortFilterProxyModel, I will instead lose the ability to check / uncheck my checkbox column ... although the flags are set to Qt :: ItemIsEnabled | Qt :: ItemIsUserCheckable | Qt :: ItemIsEditable ... more complicated :)

 QModelIndex GenericProxy::mapToSource(const QModelIndex & proxy) const { if(not proxy.isValid()) return QModelIndex(); if((action || checkbox)) { int column = proxy.column() - addedCount(); if(column < 0) // this index is local. return QModelIndex(); QModelIndex idx = sourceModel()->index(proxy.row(), column, mapToSource(proxy.parent())); return idx ; } QModelIndex idx = sourceModel()->index(proxy.row(), proxy.column(), mapToSource(proxy.parent())); return idx; } QModelIndex GenericProxy::mapFromSource(const QModelIndex & source) const { if(not source.isValid()) return QModelIndex(); if((action || checkbox)) { // simply add appropriate informations .. int column = source.column() + addedCount(); QModelIndex idx = index(source.row(), column, mapFromSource(source.parent())); return idx; } QModelIndex idx = index(source.row(), source.column(), mapFromSource(source.parent())); return idx; } GenericItem * GenericProxy::convert(const QModelIndex & idx) const { if(idx.isValid()) return _convert(index(idx.row(), firstRealColumn(), idx.parent())); else return _convert(idx); } // _convert doesn't take care of index not really at the rightplace_ness :) GenericItem * GenericProxy::_convert(const QModelIndex & index) const { if(not index.isValid()) return dynamic_cast<GenericModel *>(sourceModel())->convert(QModelIndex()); return static_cast<GenericItem*>(index.internalPointer()); } QModelIndex GenericProxy::parent(const QModelIndex & item) const { if(not item.isValid()) return QModelIndex(); GenericItem * child = _convert(item); if(!child) return QModelIndex(); GenericItem * parent = child->parentItem(); if(parent == _convert(QModelIndex())) return QModelIndex(); int column = addedCount(); return sourceModel()->parent(mapToSource(createIndex(item.row(), column, parent ))); } QModelIndex GenericProxy::index(int row, int column, const QModelIndex & parent) const { if( not hasIndex(row,column,parent)) return QModelIndex(); GenericItem * pitem = convert(parent); GenericItem * pchild = pitem->child(row); if(pchild) return createIndex(row, column, pchild); else return QModelIndex(); } 
0
source

All Articles