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 :

Ajout de fonctions au pilote sqlite? [QtSql]


Sujet :

PyQt Python

  1. #1
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut Ajout de fonctions au pilote sqlite?
    Bonjour,

    Je travaille souvent avec sqlite3. Même s'il n'est compatible qu'avec sql1992, il est déjà très puissant et très rapide.

    Avec le pilote Python 'normal' (module sqlite3), et grâce à 'create_function' qui fait partie de ce module, j'ajoute au moins 2 fonctionnalités qui me semblent indispensables:

    => une possibilité de tri français qui range correctement majuscules, minuscules et caractères accentués

    => une possibilité de recherche 'approximative' qui utilise SequenceMatcher du module difflib et qui pallie la pauvreté du 'like' de sqlite3.

    Ces 2 fonctionnalités sont ajoutées en code Python, mais après, elle sont activées directement dans les scripts SQL.

    Mon problème: je voudrais faire ça en QtSql et je ne trouve pas comment. Je sais qu'il y a dans le pilote sqlite3 une fonction écrite en C qui permet d'ajouter des fonctionnalités en C (http://www.sqlite.org/c3ref/create_function.html), mais je voudrais rester en Python.

    Quelqu'un a-t-il une piste?
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  2. #2
    Membre habitué Avatar de ashren
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 101
    Points : 193
    Points
    193
    Par défaut
    Bonjour,

    pas d'information en Python mais j'ai trouvé ceci en C++

    http://stackoverflow.com/questions/6...ctions-with-qt

    Si ça peut aider.

  3. #3
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Pour ashren: merci pour l'info! J'ai noté le lien, mais je voudrais d'abord chercher les solutions en Python.

    Pour l'instant, je suis en train de creuser une solution qui passe par 'QtGui.QSortFilterProxyModel'. C'est effectivement une sorte de proxy qui s'interpose entre le QSqlRelationalTableModel et le QTableView, et qui permet de modifier les fonctions de tri et de filtrage.

    Je découvre petit à petit, mais, par exemple, je constate que la méthode 'setSortLocaleAware(True)' appliquée au proxy permet effectivement le tri selon le dictionnaire français (avec une locale française!). Peut-être que mon 1er point est résolu, mais je continue à tester.

    Pour le filtrage, il semble qu'il y ait des possibilités de regex et de joker?? A creuser. Mais je n'ai pas encore vu de solution de type SequenceMatcher avec un ratio.

    Si quelqu'un a des infos sur la mise en oeuvre de ce proxy 'QtGui.QSortFilterProxyModel', y compris pour le modifier par sous-classement: je suis très intéressé!
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  4. #4
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut Ajout de méthodes supplémentaires de tri et filtrage
    Bonjour,

    Ça y est: j'ai tout trouvé!!! Et même des choses que je ne cherchais pas

    Effectivement le simple modèle QSqlRelationalTableModel alimentant le QTableView en données provenant d'une table de base de données a des capacités de tri et filtrage limitées. Pour le tri, c'est dans l'ordre des caractères de la police, c'est à dire: majuscules, puis minuscules, puis caractères accentués. Pour le filtrage, c'est une expression SQL qui sera précédée de 'WHERE' (et c'est bien que ça existe!).

    Pour ajouter des méthodes de tri et de filtrage plus sophistiquées, il faut utiliser un QSortFilterProxyModel(), et l'intercaler entre le QSqlRelationalTableModel et le QTableView.

    Par exemple:

    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
    # création du modèle
    self.model = QSqlRelationalTableModel(self, self.cnx) # cnx = connexion ouverte sur la base
    self.model.setTable(self.table) # table=nom de la table à afficher
    self.model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
    self.model.select() # peupler le modèle
     
    # création du proxy
    self.proxy = QtGui.QSortFilterProxyModel()
    self.proxy.setSortLocaleAware(True) # trier selon le dico français
    self.proxy.setSourceModel(self.model) # alimenter le proxy par le modèle
     
    # création de la table pour affichage
    self.vue = QtGui.QTableView(self)
    self.vue.setModel(self.proxy) #alimenter le QTableView par le proxy
    self.vue.setItemDelegate(QtSql.QSqlRelationalDelegate(self.vue))
    self.vue.setSortingEnabled(True) # active le tri en cliquant en haut des colonnes
    self.proxy.sort(-1) # tri selon l'ordre de saisie des lignes de la base
    self.vue.resizeColumnsToContents()
    Vous voyez dans ce petit code comment les éléments sont accrochés:

    base de données => modèle => proxy => tableau d'affichage
    - pour le tri selon le dictionnaire français, il suffit de mettre la ligne: "self.proxy.setSortLocaleAware(True)": simple, non? En pratique, il suffira de cliquer sur la case d'entête d'une colonne pour que le tri se fasse. Je n'ai pas encore cherché comment faire des tris multicolonnes (comme Excel), mais j'en aurai besoin à l'occasion.

    Imaginons maintenant que je veuille faire un tri plus complexe. Par exemple, j'ai une colonne de dates présentées sous forme de chaines de caractères comme "19/7/12", et j'aimerais les trier dans l'ordre des dates croissantes. Vous voyez que ce n'est pas possible en triant simplement les chaines. La solution: sous-classer QSortFilterProxyModel et surcharger la méthode lessThan.

    Voilà un code de principe:

    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
    class MonProxyModel(QtGui.QSortFilterProxyModel):
        """ProxyModel pour ajouter des méthodes de tri et de filtrages particuliers
           s'interpose entre le model et le QTableView
        """
        #========================================================================
        def __init__(self, parent=None):
            super(MonProxyModel, self).__init__(parent)
        #========================================================================
        def lessThan(self, left, right):
            """pour utiliser une fonction de comparaison particulière
               left et right: QModelIndex
               retourne un booléen (True si left<right)
            """
            role = self.sortRole()
            left = left.data(role).toPyObject()
            right = right.data(role).toPyObject()
            if isinstance(left, QtCore.QString) and isinstance(right, QtCore.QString):
                return compare(unicode(left), unicode(right)) < 0
            else:
                return left < right
    Pour s'adapter à un tri spécifique comme celui des dates, il suffira de créer la fonction de comparaison appelée ici "compare(unicode(left), unicode(right))". Vous voyez que ça marche un peu comme l'argument "cmp" de la méthode sort, à part que la méthode lessThan doit renvoyer un booléen et non un résultat comme cmp (nb<0, nb=0, nb>0). D'où le "compare(...) < 0".


    Pour le filtrage, grâce à QSortFilterProxyModel(), on récupère 2 méthodes: le filtrage par expression régulière (regex), et le filtrage par wildcard (=joker).

    Le filtrage par regex fonctionne bien, et voilà une petite fonction pour la lancer:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        def filtreRegex(self, motif, col=-1, okcasse=True):
            """filtre la table avec expression régulière sur une colonne ou toutes"""
            # colonne sur laquelle le filtrage s'exerce (-1=toutes)
            self.proxy.setFilterKeyColumn(col)
            # prépa de l'argument: tenir compte ou non de la casse (majusc/minusc)
            casse = [QtCore.Qt.CaseInsensitive, QtCore.Qt.CaseSensitive][int(okcasse)]
            # configuration de l'objet QRegExp
            rx = QtCore.QRegExp(motif, casse, QtCore.QRegExp.RegExp)             
            # filtre!
            self.proxy.setFilterRegExp(rx)
    Pour le filtrage par wilcard, il existe, mais malheureusement, il est buggué: par exemple la recherche avec le motif "MR*" dans la chaine "VBMïvfHMRwüésBTùTMXG" la sélectionnera à cause du "MR" interne, alors qu'elle ne devrait pas puisqu'elle commence par "VB". C'est un bug reconnu et il sera (peut-être?) résolu dans les prochaines versions de QT4.

    Qu'à cela ne tienne: on va maintenant non seulement corriger ce bug, mais ajouter un filtrage par recherche de mots similaires (avec un ratio de similitude)!

    Il "suffit" pour cela d'utiliser le sous-classement de QSortFilterProxyModel que nous avons fait pour le tri, et de surcharger la méthode filterAcceptsRow qui est appelée à chaque ligne pour savoir si elle doit être retenue dans le filtrage ou pas.

    Commençons par la correction du wildcard. Il s'agit de remplacer la méthode défaillante de Qt4 par la méthode fnmatchcase (qu'on nommera ici "okWildcard") du module fnmatch:

    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
    68
    69
    70
    71
    72
    73
    74
    from fnmatch import fnmatchcase as okWildcard
     
    #############################################################################
    class MonProxyModel(QtGui.QSortFilterProxyModel):
        """ProxyModel pour ajouter des méthodes de tri et de filtrages particuliers
           s'interpose entre le model et le QTableView
        """
     
        #========================================================================
        def __init__(self, parent=None):
            super(MonProxyModel, self).__init__(parent)
            # initialise le filtre simil mais le désactive par défaut
     
        #========================================================================
        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]:
                # correction du bug Qt des wildcards et wildcards Unix
     
                # mot 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 = majusc_sans_accent(motif)
                # role de filtrage
                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
     
                    # 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 = majusc_sans_accent(item)
                    # retour du résultat de la comparaison de l'item avec le motif
                    return okWildcard(item, motif)
     
                else:
                    # ici, le filtrage s'exerce sur toutes les colonnes
     
                    # nombre total de colonnes
                    nbcol = self.columnCount(sourceParent)
                    # traitement de toutes les colonnes
                    for col in xrange(0, nbcol):
                        # 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 = majusc_sans_accent(item)
                        # il suffit d'un seul résultat=True pour retenir la ligne
                        if okWildcard(item, motif):
                            return True
     
                    # ici, aucun item des colonnes n'a donné un résultat satisfaisant
                    return False
     
            #--------------------------------------------------------------------
            else:
                # exécution du filtrage prédéfini
                return QtGui.QSortFilterProxyModel.filterAcceptsRow(self, sourceRow, sourceParent)
    NB: c'est le tout dernier 'else' qui permettra au filtrage par regex de continuer à fonctionner!

    Pour les comparaisons demandées "sans tenir compte de la casse", je passe le mot et le motif en majuscules, mais il y a un petit problème: la méthode .upper() si pratique garde les accents sur les majuscules. J'ai donc fait une petite fonction qui supprime ces accents en utilisant unicodedata:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    import unicodedata
     
    def majusc_sans_accent(ch):
        """Convertit la chaine ch (unicode) en majuscules non accentuées """
        # conversion en majuscules 
        ch = ch.upper()
        # suppression des accents qui restent sur les majuscules
        chnorm = unicodedata.normalize('NFKD', ch)
        return u"".join([c for c in chnorm if not unicodedata.combining(c)])
    Voilà un exemple de fonction qui lancera un tel filtrage:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        def filtreJoker(self, motif, col=-1, okcasse=True):
            """filtre la table avec un motif joker sur une colonne ou toutes"""
            # colonne sur laquelle le filtrage s'exerce (-1=toutes)
            self.proxy.setFilterKeyColumn(col)
            # prépa de l'argument: tenir compte ou non de la casse (majusc/minusc)
            casse = [QtCore.Qt.CaseInsensitive, QtCore.Qt.CaseSensitive][int(okcasse)]
            # crée et configure l'objet QRegExp
            rx = QtCore.QRegExp(motif, casse, QtCore.QRegExp.WildcardUnix)             
            # filtre!
            self.proxy.setFilterRegExp(rx)
    Vous voyez que pour avoir ce filtrage, il faut 3 éléments:

    - le motif de filtrage comme, par exemple, u"Tot?*.txt"
    - l'index de la colonne concernée: 0, 1, 2, ... (-1 pour toutes les colonnes)
    - le fait que la comparaison soit faite en tenant compte de la casse ou pas (majusc/minusc).

    Passons maintenant au filtrage par similitude de mots.

    On utilise SequenceMatcher du module difflib:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from difflib import SequenceMatcher
     
    def simil(mot1, mot2, ratio=0.70, okmajusc=True):
        """compare 2 mots, et retourne True si le taux de similitude est >= au ratio
           okmajusc=True permet ne ne pas tenir compte de la casse (passage en majuscules) 
        """
        if okmajusc:
            mot1 = majusc_sans_accent(mot1)
            mot2 = majusc_sans_accent(mot2)
        return SequenceMatcher(None, mot1, mot2).ratio() >= ratio
    Pour utiliser ça on va, à l'intérieur de la classe sous-classant QSortFilterProxyModel:

    - ajouter un drapeau à l'initialisation de la classe pour signaler que le test des lignes par filterAcceptsRow devra se faire avec le test des similitudes

    - ajouter dans ce cas le traitement de chaque ligne à l'intérieur de la méthode filterAcceptsRow

    Voilà un exemple de code qui fait ça:

    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
    68
    69
    70
    71
    72
    73
    74
    75
    76
     
    class MonProxyModel(QtGui.QSortFilterProxyModel):
        """ProxyModel pour ajouter des méthodes de tri et de filtrages particuliers
           s'interpose entre le model et le QTableView
        """
     
        #========================================================================
        def __init__(self, parent=None):
            super(MonProxyModel, self).__init__(parent)
            # initialise le filtre simil mais le désactive par défaut
            self.filtreSimil()
     
        #========================================================================
        def filtreSimil(self, oksimil=False, ratiosimil=0.70):
            """configure le filtre simil"""
            self.oksimil = oksimil
            self.ratiosimil = ratiosimil
        #========================================================================
        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.oksimil:
                # filtrage par comparaison similaire avec ratio de similitude
     
                # mot de référence à comparer pour le filtrage
                mot = unicode(self.filterRegExp().pattern())
                # récup du drapeau qui dit si on filtre en tenant compte de la case
                okmajusc = (self.filterCaseSensitivity()==0)
                # role de filtrage
                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
     
                    # fonction d'index de la ligne et de la colonne en cours
                    index = self.sourceModel().index(sourceRow, col, sourceParent)
                    # valeur à filtrer
                    #item = unicode(self.sourceModel().data(index, QtCore.Qt.DisplayRole).toString())
                    item = unicode(self.sourceModel().data(index, role).toPyObject())
     
                    # retour selon le résultat du test de similitude
                    return simil(item, mot, self.ratiosimil, okmajusc)
     
                else:
                    # ici, le filtrage s'exerce sur toutes les colonnes
     
                    # nombre total de colonnes
                    nbcol = self.columnCount(sourceParent)
                    # traitement de toutes les colonnes
                    for col in xrange(0, nbcol):
                        # 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, QtCore.Qt.DisplayRole).toString())
                        item = unicode(self.sourceModel().data(index, role).toPyObject())
     
                        # il suffit d'un seul résultat=True pour retenir la ligne
                        if simil(item, mot, self.ratiosimil, okmajusc):
                            return True
                    # ici, aucun item des colonnes n'a donné une similitude suffisante
                    return False
     
            #--------------------------------------------------------------------
            # on peut ajouter ici la partie "filtrage par wildcard" avec un elif                
     
            #--------------------------------------------------------------------
            else:
                # exécution du filtrage prédéfini
                return QtGui.QSortFilterProxyModel.filterAcceptsRow(self, sourceRow, sourceParent)
    Et voilà une fonction qui appelle ce filtrage par similitude:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        def filtreSimil(self, motif, col=-1, okcasse=True, ratio=0.70):
            """filtre la table avec un motif de similitude sur une colonne ou toutes"""
            # active le filtrage par similitude
            self.proxy.filtreSimil(True, ratio)
            # donne la colonne sur laquelle le filtrage s'exerce (-1=toutes)
            self.proxy.setFilterKeyColumn(col)
            # prépa de l'argument: tenir compte ou non de la casse (majusc/minusc)
            casse = [QtCore.Qt.CaseInsensitive, QtCore.Qt.CaseSensitive][int(okcasse)]
            # crée et configure l'objet QRegExp
            rx = QtCore.QRegExp(motif, casse, QtCore.QRegExp.RegExp)             
            # filtre!
            self.proxy.setFilterRegExp(rx) 
            # désactive le filtre par similitude
            self.proxy.filtreSimil(False)
    On voit ce qui est nécessaire pour faire fonctionner ce filtrage:

    - le motif: le mot que je cherche. Par exemple, je cherche "Wang", et il me trouvera: "Tang", "Wong", "Wank", etc... qu'on trouverait difficilement par un autre moyen de filtrage
    - la colonne (0, 1, 2, ...) sur laquelle le filtrage se fera. Si -1, il se fera sur toutes les colonnes.
    - le fait de tenir compte ou non de la casse
    - le ratio de similitude: =1.0 pour une correspondance parfaite, =0.70 ou =0.80 pour la détection de faute de frappe à la saisie, =0.50 pour une recherche très large. En dessous de 0.50, ça attrape trop de chose.

    En fait, j'utilise cette méthode pour chercher des infos dans la base de données en tenant compte d'éventuelles fautes de frappe.

    Ouf... Voilà, j'espère que je n'ai rien oublié d'important!

    Je ne sais pas s'il y a beaucoup de personnes intéressées par ce sujet, mais j'ai dû consulter une centaine de sites web, essentiellement en anglais, ainsi que plusieurs livres sur PyQt4 et Qt4 en C++, et je n'ai pas trouvé grand chose d'exploitable...
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  5. #5
    Membre habitué Avatar de ashren
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 101
    Points : 193
    Points
    193
    Par défaut
    Super intéressant !

    pour l'histoire du MR*, tu as essayé avec "^MR*" ?

  6. #6
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour ashren,

    Oui, bien sûr, j'ai essayé ça. Mais le '^' n'a pas de signification fonctionnelle dans la syntaxe des wildcards: il cherche le caractère '^'.

    Pour le bug des wildcards: on peut le mettre en évidence dans l'une des démos livrées avec PyQt4: item views => basic sort/filter model. Un filtrage par 'S*' ramasse 'Linda...' et 'Petra...'.

    A noter que Qt4 fait la distinction entre 'Wildcard' et les 'WildcardUnix', et moi j'ai corrigé les 2 en 'WildcardUnix' par simplification puisque c'est ce que fait le module fnmatch.
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  7. #7
    Membre habitué Avatar de ashren
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 101
    Points : 193
    Points
    193
    Par défaut
    D'accord, je n'avais pas percuté que tu parlais des wildcards.

  8. #8
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Juste un petit complément à ce qui précède.

    Je me suis aperçu qu'en utilisant le proxy QSortFilterProxyModel pour améliorer les tri et filtrages, on perdait quelque chose: à l'affichage du QTableView, les colonnes ayant des contraintes de clé étrangère n'étaient plus éditées par des QComboBox, mais par de simple QLineEdit.

    Cependant, la contraite est respectée, puisque la tentative d'introduire une donnée qui ne respecte pas cette contrainte se traduit par un simple refus (pas de message d'erreur, mais l'ancienne donnée vient remplacer la donnée modifiée à l'affichage).

    Mais c'est quand même dommage: la saisie par combobox est très pratique et permet d'éviter des fautes de frappes.

    Pour retrouver l'édition par combobox, j'ai trouvé une solution: sous-classer QSqlRelationalDelegate et surcharger ses méthodes createEditor, setEditorData et setModelData.

    Si quelqu'un est intéressé, je peux donner le code.
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 08/01/2007, 14h13
  2. Ajout de fonction C pour PHP
    Par syl2095 dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 2
    Dernier message: 16/10/2006, 11h41
  3. requete ajout en fonction de la valeur d'un champ ?
    Par mat75019 dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 22/06/2006, 10h17
  4. Réponses: 13
    Dernier message: 06/02/2006, 10h12
  5. [VBA-E] Ajouter des fonctions dans Excel
    Par Clezio dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 06/03/2004, 01h18

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