IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Qt Discussion :

QStandardItemModel : filtrer sur plusieurs colonnes


Sujet :

Qt

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 32
    Points : 22
    Points
    22
    Par défaut QStandardItemModel : filtrer sur plusieurs colonnes
    Bonjour,

    J'ai établit un QStandardItemModel pour stocker mes données et je souhaite filtrer cette liste sur plusieurs colonnes.
    Par exemple :
    Nom (colonne 0) : Dupond
    Prénom (colonne 1) : Jean

    J'y arrive sur une colonne mais je ne vois pas comment faire avec plusieurs colonnes... Une idée ?

  2. #2
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Points : 25
    Points
    25
    Par défaut
    Hello,

    tu peux utiliser un QSortFilterProxyModel. Tu définis le source model à ce proxy par la méthode setSourceModel().
    Ici ton source model c'est ton QStandardItemModel.
    Une fois ceci fait, tu set ce proxy comme model de ta view.
    Ensuite tu peux filter le contenu de ton modèle grace aux méthodes :
    - QSortFilterProxyModel::setFilterKeyColumn() pour définir quelle colonne tu veux filtrer (nom, prénom...)
    - QSortFilterProxyModel::setFilterRegExp() pour définir ton pattern de filtrage.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 32
    Points : 22
    Points
    22
    Par défaut
    Citation Envoyé par Bezu_Menez Voir le message
    - QSortFilterProxyModel::setFilterKeyColumn() pour définir quelle colonne tu veux filtrer (nom, prénom...)
    - QSortFilterProxyModel::setFilterRegExp() pour définir ton pattern de filtrage.
    C'est ce que j'ai fait pour filtrer sur la colonne "Nom" de cette façon :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void OngletSaisie::filtrageNom(QString nouveauTexte)
    {
        QSortFilterProxyModel *modeleFiltre = new QSortFilterProxyModel() ;
     
        modeleFiltre->setSourceModel(m_modeleInscrits);
        modeleFiltre->setFilterKeyColumn(1) ;
        modeleFiltre->setFilterFixedString(nouveauTexte) ;
     
        vueResultats->setModel(modeleFiltre) ;
    }
    Mais si je fais la même chose avec setFilterKeyColumn(2), à quoi s'applique la méthode setFilterFixedString() ?
    Ça n'annule pas mon précédent filtre ?

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Points : 25
    Points
    25
    Par défaut
    Mais si je fais la même chose avec setFilterKeyColumn(2), à quoi s'applique la méthode setFilterFixedString() ?
    Ça n'annule pas mon précédent filtre ?
    Elle s'applique sur la 3ème colonne (tout index de colonne commence par 0).

    En effet cela va annuler ton précédent filtre. Je ne sais pas trop ce que tu veux faire, mais si tu comptes appliquer 2 filtres (l'un sur la 1er colonne puis l'autre sur la seconde colonne), il faut utiliser une chaine de proxys.

    Au lieu de setter le proxymodel sur ta vue
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    vueResultats->setModel(modeleFiltre) ;
    tu vas utiliser ce proxy comme sourcemodel() d'une nouvelle instance de QSortProxyModel. Sur cette nouvelle instance, tu vas définir le filterKeyColumn à la troisième colonne.

    Et c'est ce nouveau proxy que tu vas donner à ta vue vueResultats (car comme tu l'as remarqué dans ton précédent code, un proxy est une classe dérivée de QAbstractItemModel).
    Si je schématise ta chaine de model ca donne un truc comme ca :

    QStandardItemModel <- QSortFilterProxyModel (1) <- QSortFilterProxyModel (2) <- QAbstractItemView

    avec QSortFilterProxyModel (1) : proxy qui filtre la 1ere colonne
    avec QSortFilterProxyModel (2) : proxy qui filtre la 2eme colonne

    Bonne chance !

    Ps : remplace
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void OngletSaisie::filtrageNom(QString nouveauTexte)
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void OngletSaisie::filtrageNom(const QString & nouveauTexte)

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 32
    Points : 22
    Points
    22
    Par défaut
    J'ai bien saisi, l'explication est très claire. Mais j'essaie déjà d'aller plus loin et de réfléchir à plus de souplesse.
    Je vais avoir au minimum 4 colonnes possible à filtrer.

    Je pense créer dans le constructeur la source, et un proxy de filtre actuel et un nouveau.

    Ensuite pour chaque slot lié à mes signaux de champs de recherche (textChanged), je définis le nouveau filtre avec comme source le filtre en cours.
    Mais la ou je bloque, c'est pour à nouveau établir le nouveau filtre comme filtre en cours (une copie ? ça risque d'être long).

    Je posterai le résultat de mes expériences dès que possible.

    Citation Envoyé par Bezu_Menez Voir le message
    Ps : remplace
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void OngletSaisie::filtrageNom(QString nouveauTexte)
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void OngletSaisie::filtrageNom(const QString & nouveauTexte)
    Oui, merci, c'est toujours mieux de bien établir ces détails car après on oublie...

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Points : 25
    Points
    25
    Par défaut
    J'ai pas tout compris...

    T'as une treeview avec 4 colonnes minimum. Tu associes donc un champ QLineEdit par colonne pour pouvoir associer plusieurs filtres par colonne ?
    Plutot que de créer un proxy à chaque textChanged(), tu n'as qu'à créer la chaine de proxys dans le constructeur. Chaque proxy est ainsi conservé en variable membres de ta classe.
    Chaque textChanged() viendra modifier, via la méthode setFilterFixedString(), le proxy concerné.

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 32
    Points : 22
    Points
    22
    Par défaut
    Citation Envoyé par Bezu_Menez Voir le message
    J'ai pas tout compris...

    T'as une treeview avec 4 colonnes minimum. Tu associes donc un champ QLineEdit par colonne pour pouvoir associer plusieurs filtres par colonne ?
    Plutot que de créer un proxy à chaque textChanged(), tu n'as qu'à créer la chaine de proxys dans le constructeur. Chaque proxy est ainsi conservé en variable membres de ta classe.
    Chaque textChanged() viendra modifier, via la méthode setFilterFixedString(), le proxy concerné.
    C'est ce que j'ai fini par faire... Mais je trouve ça un peu lourd : avec 4 colonnes à filtrer, ça passe encore mais avec une quinzaine...
    Voici mon code pour ceux que ça intéresse :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    OngletSaisie::OngletSaisie(QStandardItemModel *modele, QWidget *parent) :
        QWidget(parent), m_modeleInscrits(modele)
    {
        setupUi(this);
     
        // Mise en place des filtres en chaine
        m_filtreNom = new QSortFilterProxyModel() ;
        m_filtreAS = new QSortFilterProxyModel() ;
        m_filtreVille = new QSortFilterProxyModel() ;
        m_filtreNom->setSourceModel(m_modeleInscrits);
        m_filtreAS->setSourceModel(m_filtreNom);
        m_filtreVille->setSourceModel(m_filtreAS);
     
        // L'affichage est lié au dernier filtre de la chaine
        vueResultats->setModel(m_filtreVille) ;
     
        // Connexion des filtres
        connect(filtreNom,SIGNAL(textChanged(QString)), this, SLOT(filtrageNom(QString))) ;
        connect(filtreAS,SIGNAL(textChanged(QString)), this, SLOT(filtrageAS(QString))) ;
        connect(filtreVille,SIGNAL(textChanged(QString)), this, SLOT(filtrageVille(QString))) ;
     
    }
     
    void OngletSaisie::filtrageNom(const QString &nom)
    {
        m_filtreNom->setFilterKeyColumn(1) ;
        m_filtreNom->setFilterFixedString(nom) ;
    }
     
    void OngletSaisie::filtrageAS(const QString &AS)
    {
        m_filtreAS->setFilterKeyColumn(6) ;
        m_filtreAS->setFilterFixedString(AS) ;
    }
    void OngletSaisie::filtrageVille(const QString &ville)
    {
        m_filtreAS->setFilterKeyColumn(8) ;
        m_filtreAS->setFilterFixedString(ville) ;
    }
    Je pensais éviter la déclaration de multiples filtres en en déclarant simplement 2. Un filtreEnCours (basé sur mon modèle source) et à chaque fois qu'un critère est saisi, un filtreNouveau est créé (basé sur le filtreEnCours) et vient peupler et remplacer le filtreEnCours.

    Mais je ne voit pas comment remplacer le filtreEnCours autrement qu'en recopiant les items depuis filtreNouveau vers filtreEnCours.

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 13
    Points : 25
    Points
    25
    Par défaut
    En effet développé comme ca, ton code va vite ressemblé à un champ de mines.
    Maintenant rien ne t'empeche de gérer une QList<QAbstractItemModel*>
    Cette liste est un pipe contenant l'ensemble de tes proxys.
    La construction de ce pipe est simple puisque :
    • Le premier élément du pipe est notre modèle de base (ton QStandardItemModel),
    • Chaque élément i du pipe posséde comme sourcemodel() l'élément i-1 (sauf quand i == 0),
    • Le dernier élement servira de model Qt pour la view.


    On peut gérer aussi choisir de gérer une QList<QAbstractProxyModel*> si tu considères que cette liste ne contient que tes proxy models et jamais ton modèle standard. Ca peut peut être éviter quelques casts foireux basé sur la position de ton modèle dans la liste. A voir avec le code résultant de tout ca.

Discussions similaires

  1. Filtrer les doublons sur plusieurs colonnes
    Par henri228 dans le forum Conception
    Réponses: 2
    Dernier message: 07/05/2010, 22h21
  2. trier un stringgrid sur plusieurs colonnes
    Par renegade55 dans le forum Composants VCL
    Réponses: 2
    Dernier message: 13/12/2005, 16h30
  3. Jointure avec conditions sur plusieurs colonnes
    Par ben53 dans le forum Langage SQL
    Réponses: 9
    Dernier message: 28/11/2005, 09h27
  4. Lister sur plusieurs colonnes dans état
    Par armagued dans le forum Access
    Réponses: 3
    Dernier message: 30/10/2005, 21h21
  5. Query sur plusieurs colonnes avec count(distinct...)
    Par Jeankiki dans le forum Langage SQL
    Réponses: 2
    Dernier message: 18/08/2004, 15h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo