2010-09-16 3 views
4

J'utilise un QSortFilterProxyModel pour filtrer les résultats d'un QAbstractListModel. Cependant, je voudrais retourner une première entrée qui n'est pas présente dans le modèle original, c'est-à-dire, c'est artificiel.QSortFilterProxyModel retourne la ligne artificielle

C'est ce que j'ai jusqu'à présent:

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 

Ceci renvoie une liste sous forme de:

Account 1 
Account 2 
... 

Id » comme retourner un élément supplémentaire au début du retour liste des éléments f:

Extra Element 
Account 1 
Account 2 
... 

J'ai essayé de ré-écrire rowCount pour retourner le vrai rowCount() + 1, mais en quelque sorte, je serais besoin de décalage tous les éléments afin de retourner cet élément artificiel à l'index 0, et je suis un peu perdu là-bas.

Une idée? Je n'ai pas trouvé d'exemple de code lié jusqu'à présent ... Merci!

+0

Je ne suis pas sûr que le QSortFilterProxyModel est le meilleur endroit pour essayer de le faire. Les termes opératifs étant _sort_ et _filter_. Je pense que faire cela dans un modèle personnalisé serait mieux. –

Répondre

1

Je l'ai fait, seulement au travail, donc je ne peux pas vous donner beaucoup de code. Je peux vous donner l'idée générale de ce qu'il faut faire.

Cela fonctionne mieux si vous sous-classe QAbstractProxyModel, qui est conçu pour la manipulation générale, pas le tri ou le filtrage. Vous aurez besoin de surcharger rowCount, et aussi de surcharger columnCount (bien que cela devrait juste retourner les informations du modèle source). Vous devrez remplacer la fonction de données et renvoyer vos propres données pour la première ligne, ou appeler le modèle source une fois de plus. Vous devez remplacer les fonctions mapFromSource et mapToSource pour permettre la permutation entre les index de modèle de proxy et les index de modèle source. Pour une implémentation robuste, vous devez créer des emplacements et vous connecter aux signaux du modèle source pour le changement de données, la réinitialisation du modèle et les lignes/colonnes sur le point d'être insérées/supprimées. Vous devriez alors émettre vos propres signaux, en les adaptant correctement pour tenir compte de votre rangée supplémentaire.

Dans notre classe, nous avons paramétré le texte pour la première ligne, afin que nous puissions utiliser le même modèle de proxy dans différentes situations. Cela vaut la peine d'enquêter pour le vôtre, car cela ajoute un effort minimal.

Modifier

Per a commenté la demande, un aspect rugueux à mapToSource et mapFromSource. C'est à peu près ce à quoi vous devez penser.

// Remember that this maps from the proxy's index to the source's 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) 
+0

Je suis allé sur ce chemin aussi, mais je me suis un peu perdu avec les fonctions mapFrom/mapTo: -S Pouvez-vous ajouter plus de détails à ce sujet, même si vous ne pouvez pas afficher le code? L'idée générale devrait suffire :-) Merci! – saghul

+1

Merci beaucoup! – saghul

2

Parce que je luttais un peu avec la mise en œuvre de cela et parce que je ne pouvais pas trouver un autre exemple de code dans le filet entier, je poste cette mise en œuvre de l'échantillon.

J'espère que cela aide les autres aussi ...

/** 
** 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(); 
} 

Cordialement Sven

0

j'ai eu le même genre de problème récemment, et ont beaucoup de problèmes avec les parents et Maping avec le modèle source .

Ma version doit gérer des colonnes virtuelles à gauche, quelques unes liées à des actions, et éventuellement une qui est une case à cocher.

Espoirs cela peut aider quelqu'un aussi :)

Pourtant, une note aux sages, je suis un sous-classement QSortFilterProxyModel, et ce faisant, il me semble perdre la capacité d'utiliser sorte. Je suppose que c'est parce que je remplace les méthodes d'index/données. Si je devais plutôt sous-classer QIdentityProxyModel et ensuite ajouter un QSortFilterProxyModel par la suite, je perds la possibilité de cocher/décocher la case checkbox ... même si les flags sont définis sur Qt :: ItemIsEnabled | Qt :: ItemIsUserCheckable | Qt :: ItemIsEditable ... délicat encore :)

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(); 

} 
Questions connexes