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

PyQt Python Discussion :

Filtre exclusion dans un QSortFilterProxyModel [QtGui]


Sujet :

PyQt Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Octobre 2008
    Messages
    330
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 330
    Par défaut Filtre exclusion dans un QSortFilterProxyModel
    Bonjour à Tous,
    Je créé des filtres personnalisés dans un QTableView à travers un QSortFilterProxyModel. Pas de problèmes pour les filtres classiques, j'utilise
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    self.proxy.setFilterKeyColumn(self.column)
    self.proxy.setFilterWildcard(pattern)
    et çà fonctionne bien. Par contre je n'arrive pas à créer un filtre d'exclusion. C'est à dire n'afficher que les valeurs différentes d'un pattern défini (une chaine, un nombre, une date). J'ai fait pas mal de recherche sur le net mais je n'ai rien trouvé de vraiment exploitable. Quelqu'un aurait t-il une piste ?
    Merci d'avance pour vos idées.
    Cordialement,

  2. #2
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    On pourrait, bien sûr, utiliser les regex (QRegExp) avec la syntaxe des regex du perl, mais ce serait plus compliqué.

    En restant dans les wildcards, la solution serait de:
    - sous-classer le QSortFilterProxyModel
    - surcharger sa méthode filterAcceptsRow

    Cette méthode est appelée à chaque ligne. Pour chaque ligne, on fait tous les tests qu'on veut, et on retourne True ou False selon que la ligne doit être conservée dans le filtrage ou pas.

    J'applique moi-même cette solution, et j'utilise en fait le wildcard de Python (fonction fnmatchcase du module fnmatch) qui correspond à la syntaxe Unix. Et si l'option "ne pas tenir compte de la casse" est vraie, je mets le motif et la ligne en majuscules avant de faire le test.

    Cela pourrait donner quelque chose comme ça (extrait de mon code en Python 2.7 et Qt4):

    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
     
    import sys
    from fnmatch import fnmatchcase
    from PyQt4 import QtCore, QtGui, QtSql
     
    #############################################################################
    class MonProxyModel(QtGui.QSortFilterProxyModel):
        """ProxyModel pour ajouter des méthodes de tri et de filtrages particuliers
           s'interpose entre le modèle et le QTableView
        """
     
        #========================================================================
        def __init__(self, parent=None):
            super(MonProxyModel, self).__init__(parent)
     
        #========================================================================
        def filterAcceptsRow(self, sourceRow, sourceParent):
            """Surcharge de la méthode de filtrage des lignes de la table
               source_row: int 
               source_parent: QModelIndex
               retour: True si la ligne est retenue, False sinon
            """
     
            #--------------------------------------------------------------------
            if self.filterRegExp().patternSyntax() in [QtCore.QRegExp.Wildcard, QtCore.QRegExp.WildcardUnix]:
     
                # motif de référence à comparer pour le filtrage
                motif = unicode(self.filterRegExp().pattern())
                # récup du drapeau qui dit si on filtre en tenant compte de la case
                okmajusc = (self.filterCaseSensitivity()==0)
                # correction du motif si on ne tient pas compte de la case
                if okmajusc:
                    motif = motif.upper()
                # rôle du filtrage (par défaut: QtCore.Qt.DisplayRole)
                role = self.filterRole()
                # index de la colonne sur laquelle s'exerce le filtrage (-1=toutes)
                col = self.filterKeyColumn()
     
                if col>=0:
                    # ici, le filtrage ne s'exerce que sur la colonne d'index col
                    col1, col2 = col, col+1
                else:
                    # ici, le filtrage s'exerce sur toutes les colonnes
                    col1, col2 = 0, self.columnCount(sourceParent)
     
                # traitement de la ou des colonne(s)
                for col in xrange(col1, col2):
                    # fonction d'index de la ligne en cours d'examen
                    index = self.sourceModel().index(sourceRow, col, sourceParent)
                    # valeur à filtrer de la ligne en cours
                    item = unicode(self.sourceModel().data(index, role).toString())
                    # correction de l'item si on ne tient pas compte de la case
                    if okmajusc:
                        item = item.upper()
                    # si plusieurs colonnes: il suffit d'un seul résultat=True pour retenir la ligne
                    if fnmatchcase(item, motif):
                        return True
     
                # ici, aucun item n'a donné un résultat satisfaisant
                return False
     
            #--------------------------------------------------------------------
            else:
                # exécution du filtrage prédéfini
                return QtGui.QSortFilterProxyModel.filterAcceptsRow(self, sourceRow, sourceParent)
    Pour s'adapter à la question posée, il suffirait d'inverser les résultats du wildcard.

    En utilisant cette solution, on peut faire tout ce qu'on veut comme filtrage. J'utilise en plus et de la même façon un filtrage par mots similaires (avec ratio de similitude) pour trouver des noms qui auraient été saisis avec des fautes de frappe, en utilisant la fonction SequenceMatcher du module Python difflib: c'est très pratique et ça marche très bien.

  3. #3
    Membre éclairé
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Octobre 2008
    Messages
    330
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 330
    Par défaut
    Bonsoir,
    Merci Tyrtamos pour tes explications et ton morceau de code. Je l'ai adapté à mon cas. Je l'ai pas encore vraiment optimisé. Pour inverser le motif j'insère en début de chaine un "!". :
    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
     
        def filterAcceptsRow(self, sourceRow, sourceParent):
            print "filterAcceptsRow"
            motif = unicode(self.filterRegExp().pattern())
            if motif == '':
                return True
            # Extraction du 1° caractère du motif. si prem == "!" alors on prendra l'inverse du résultat
            prem = motif[0:1]
            col = self.filterKeyColumn()
            index = self.sourceModel().index(sourceRow, col, sourceParent)
            item = self.sourceModel().data(index, Qt.UserRole)
            if not item:
                item = u''
            # Test du type de donnée pour adapter le filtre
            if isinstance(item, QtCore.QDate):
                item = item.toString()
            if isinstance(item, (int, float)):
                item = unicode(item)
            if prem == '!':
                # si l'inverse du motif est détecté on enlève le 1° caractère pour trouver le motif à tester
                motif = motif[1:]
                # Test de correspondance et inversion du résultat
                if fnmatchcase(item, motif):
                    return False
                return True
            return fnmatchcase(item, motif)
    Cà fonctionne bien pour toutes les types de données. En fait, j'ai défini par ailleurs un menu contextuel spécifique pour chaque type de donnée de la QTableView qui permet de choisir le type de filtre souhaité. Pour l'instant je n'ai implémenté que des filtres "simples" : "Identique à ..." et "Différent de ..." par rapport à la cellule active. Je voudrais mettre en place des filtres plus complexes style Excel ou Access ... Pour l'instant, le prochain problème à traiter est de pouvoir conserver le filtre activé sur une colonne quand je défini un filtre sur une autre colonne. Je suis preneur de quelques pistes
    Merci à vous.
    @+

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Filtre automatique dans combobox VBA
    Par fabien114 dans le forum Macros et VBA Excel
    Réponses: 16
    Dernier message: 06/10/2008, 17h25
  2. Syntaxe pour mettre filtre personnalisé dans macro
    Par tonioj41 dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 14/02/2008, 15h06
  3. Un Filtre marche dans un PC est Pas dans un autre
    Par aliwassem dans le forum Bases de données
    Réponses: 10
    Dernier message: 25/05/2007, 16h58
  4. Réponses: 1
    Dernier message: 23/04/2007, 14h04
  5. [Excel] Récupération d'un filtre automatique dans une cellule
    Par billy123 dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 01/03/2007, 15h32

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