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

Python Discussion :

QTableWidget sorting numbers


Sujet :

Python

  1. #1
    Membre du Club
    Homme Profil pro
    ngénieur d'etat en science géodésique et travaux topographique
    Inscrit en
    Septembre 2016
    Messages
    152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : ngénieur d'etat en science géodésique et travaux topographique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Septembre 2016
    Messages : 152
    Points : 65
    Points
    65
    Par défaut QTableWidget sorting numbers
    Bonjour,
    avec PYQT5 je crée un QTableWidget qui fonctionne bien. Je veux que l'utilisateur puisse trier chaque colonne, ce qui fonctionne également, mais je n'aime pas la façon dont il trie les colonnes avec des nombres. Il triera les nombres de 0 à 10 comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    0
    1
    10
    2
    3
    4
    5
    6
    7
    8
    9
    Mais je le veux comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

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

    Sans modification, un QTableWidget ne contient que des chaînes de caractères, et c'est ce que le 1er tri montre bien. Or, tu veux un tri numérique.

    Pour obtenir le tri purement numérique, il suffit de convertir en entier. Mais tout dépend ce que tu veux obtenir: tu peux facilement trier une extraction de la colonne (.sort(key=lambda v: int(v))), mais si tu veux obtenir le tri numérique en cliquant simplement en haut de sa colonne, c'est un peu plus compliqué.

    Il y a plusieurs solutions, mais celle que j'utilise pour ça est de sous-classer QTableWidgetItem, et de surcharger sa méthode '__lt__' (=less than) pour la colonne concernée. Il faut être sûr que cette colonne ne contienne que des nombres entiers, sinon il faudra gérer les cas différents pour éviter un plantage avec la conversion int(...).

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 735
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 735
    Points : 31 060
    Points
    31 060
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par rabeh.ram Voir le message
    mais je n'aime pas la façon dont il trie les colonnes avec des nombres. Il triera les nombres de 0 à 10 comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    0
    1
    10
    2
    3
    4
    5
    6
    7
    8
    9
    Oui, parce que la string "10" est plus grande que la string "1" mais plus petite que la string "2"...
    Et il existe une section dédiée PyQt sur ce forum.

  4. #4
    Membre du Club
    Homme Profil pro
    ngénieur d'etat en science géodésique et travaux topographique
    Inscrit en
    Septembre 2016
    Messages
    152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : ngénieur d'etat en science géodésique et travaux topographique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Septembre 2016
    Messages : 152
    Points : 65
    Points
    65
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    Bonjour,
    , mais si tu veux obtenir le tri numérique en cliquant simplement en haut de sa colonne, c'est un peu plus compliqué.
    .
    C'est ce que je recherche

  5. #5
    Expert éminent
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 095
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 095
    Points : 9 581
    Points
    9 581
    Par défaut
    hello,
    en utilisant le code de tyrtamos qui se trouve ici tu peux essayer d'utiliser la fonction suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    def _human_key(key):    
        parts = re.split('(\d*\.\d+|\d+)', key)
        return tuple((e.swapcase() if i % 2 == 0 else float(e))
                for i, e in enumerate(parts))
    utilisation dans le code de tyrtamos :
    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
     
    class TableWidgetItem(QtWidgets.QTableWidgetItem): 
        # =======================================================================
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
     
            self.pasdetricols = []
     
        # =======================================================================
        def __lt__(self, other):
     
            if self.column() in self.pasdetricols:
                return False
            else:
                a = self.data(QtCore.Qt.DisplayRole)
                b = other.data(QtCore.Qt.DisplayRole)
                return (_human_key(a) < _human_key(b))
    Nom : SortQtTableWidget.gif
Affichages : 744
Taille : 37,2 Ko

    Ami calmant, J.P

  6. #6
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 483
    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 483
    Points : 9 282
    Points
    9 282
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par rabeh.ram Voir le message
    C'est ce que je recherche
    Voilà un petit code de test 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
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
     
    import sys
    from random import randint
    from PyQt5 import (QtWidgets, QtGui, QtCore)
     
     
    #############################################################################
    class TableWidgetItem(QtWidgets.QTableWidgetItem):
     
        # =======================================================================
        def __init__(self, numcol):
            super().__init__()
     
            self.numcol = numcol
     
        # =======================================================================
        def __lt__(self, other):
     
            if self.column()==self.numcol:
                a = self.data(QtCore.Qt.DisplayRole)
                b = other.data(QtCore.Qt.DisplayRole)
                return (int(a) < int(b))
            else:
                # autres colonnes
                return super().__lt__(other)
     
    #############################################################################
    class Fenetre(QtWidgets.QWidget):
     
        # =======================================================================
        def __init__(self, parent=None):
            super().__init__(parent)
     
            self.resize(600, 300)
     
            self.tableWidget = QtWidgets.QTableWidget(self)
            self.nbrow, self.nbcol = 5, 5
            self.tableWidget.setRowCount(self.nbrow)
            self.tableWidget.setColumnCount(self.nbcol)
            self.tableWidget.setSortingEnabled(True)
            self.tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)  # MultiSelection) 
     
            # numéro de colonne avec tri numérique
            self.numcol = 3
     
            # peuple le QTableWidget
            for row in range(0, self.nbrow):
                for col in range(0, self.nbcol):
                    item = TableWidgetItem(self.numcol)
                    val = str(randint(5, 15))    
                    item.setData(QtCore.Qt.DisplayRole, val)
                    self.tableWidget.setItem(row, col, item)
     
            posit = QtWidgets.QGridLayout()
            posit.addWidget(self.tableWidget, 0, 0)
            self.setLayout(posit)
     
            self.tableWidget.setFocus()
            self.tableWidget.setCurrentCell(0, 0)
     
    #############################################################################
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())
    On voit que quand on demande le tri en cliquant sur la colonne de titre "4" (=indice 3), que le tri numérique est correct, ce qui n'est pas le cas dans les autres colonnes.

  7. #7
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 735
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 735
    Points : 31 060
    Points
    31 060
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    On voit que quand on demande le tri en cliquant sur la colonne de titre "4" (=indice 3), que le tri numérique est correct, ce qui n'est pas le cas dans les autres colonnes.
    Pourquoi ne trier que la numcol=3 ? On enlève le paramètre "numcol" ainsi que le test de la ligne 21 et tout clic sur n'importe quelle colonne la trie comme il faut non ?

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

    Citation Envoyé par Sve@r Voir le message
    Pourquoi ne trier que la numcol=3 ? On enlève le paramètre "numcol" ainsi que le test de la ligne 21 et tout clic sur n'importe quelle colonne la trie comme il faut non ?
    J'ai traité le cas général dans lequel une seule colonne doit être triée numériquement. Les autres colonnes sont triées comme des chaines de caractères et ça permet de voir la différence, ce qui répond exactement à la question du PO.

  9. #9
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 735
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 735
    Points : 31 060
    Points
    31 060
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    ce qui répond exactement à la question du PO.
    En fait, comme dans son premier post il avait parlé de "...trier chaque colonne..." et "...de la façon dont il trie les colonnes..." moi j'avais pensé qu'il les voulait toutes triées numériquement.
    Bon c'est pas bien grave, l'important c'est que j'ai compris comment ça marche (j'ai beaucoup de QTableWidget dans mes projets et je vais y intégrer ton astuce) et qu'il le comprenne aussi. Ensuite trier une colonne/toutes les colonnes il verra ça lui-même.
    Merci

  10. #10
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 483
    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 483
    Points : 9 282
    Points
    9 282
    Billets dans le blog
    6
    Par défaut
    Et s'il y a plusieurs colonnes numériques, mais pas toutes, il suffit de passer une liste ou un tuple d'indices de colonnes comme argument numcol, et de changer la condition avec "if self.column() in self.numcol:".

    On peut même donner à la classe un caractère plus réutilisable dans d'autres développements, pour traiter les cas de colonnes numériques: 0, 1, plusieurs, toutes:

    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
    class TableWidgetItem(QtWidgets.QTableWidgetItem):
     
        # =======================================================================
        def __init__(self, numcol=()):
            super().__init__()
     
            self.numcol = (numecol,) if isinstance(numcol, int) else numcol
     
        # =======================================================================
        def __lt__(self, other):
     
            if self.column() in self.numcol:
                a = self.data(QtCore.Qt.DisplayRole)
                b = other.data(QtCore.Qt.DisplayRole)
                return int(a) < int(b)
            else:
                # autres colonnes non numériques
                return super().__lt__(other)

  11. #11
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 735
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 735
    Points : 31 060
    Points
    31 060
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    il suffit de passer une liste ou un tuple d'indices de colonnes comme argument numcol
    Non non, je suis déjà allé beaucoup plus loin que ça. Je passe carrément un tuple contenant le type des colonnes (ex (str, int, float). Ensuite lors de l'évaluation, le type de la colonne X est alors utilisé comme cast de la valeur de la colonne X
    Code python : 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 myTableWidgetItem(QTableWidgetItem):
    	def __init__(
    		self,
    		typeSort,
    		*args,
    		**kwargs,
    	):
    		super().__init__(*args, **kwargs)
     
    		# Les types de tri
    		self.__typeSort=typeSort
    	# __init__()
     
    	def __lt__(self, other):
    		# Colonne triée selon leur type
    		x=self.__typeSort[self.column()](self.data(Qt.DisplayRole))
    		y=other.__typeSort[self.column()](other.data(Qt.DisplayRole))
    		return x < y
    	# __lt__()
    # class myTableWidgetItem

  12. #12
    Membre du Club
    Homme Profil pro
    ngénieur d'etat en science géodésique et travaux topographique
    Inscrit en
    Septembre 2016
    Messages
    152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : ngénieur d'etat en science géodésique et travaux topographique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Septembre 2016
    Messages : 152
    Points : 65
    Points
    65
    Par défaut
    merci a tous, tout les codes fourni considérer le QTableWidget comme une class mais le QTableWidget dans mon code juste un object dans un main class

  13. #13
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 735
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 735
    Points : 31 060
    Points
    31 060
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par rabeh.ram Voir le message
    merci a tous, tout les codes fourni considérer le QTableWidget comme une class mais le QTableWidget dans mon code juste un object dans un main class
    Désolé je ne suis pas certain de bien comprendre ta phrase (ok je vois bien le français n'est pas ta langue privilégiée) donc il se pourait que je réponde à côté.
    Un QTableWidget EST une classe. C'est une classe fournie par Qt. Tu peux intégrer cet objet dans un objet plus volumineux (ce que montre le code de tyrtamos qui est un code 100% fonctionnel que tu peux récupérer et tester dans un ".py" indépendant et qui utilise un QTableWidget dans l'objet "Fenetre") mais tu peux parfaitement utiliser un QtableWidget en tant qu'objet principal.
    L'idée, c'est que le QtableWidget, quand il crée ses lignes, passe par le TableWidgetItem de tyrtamos au lieu de passer par le QTableWidgetItem standard. Ce TableWidgetItem spécial hérite d'un QTableWidgetItem (donc de toutes ses propriétés) mais possède en plus un opérateur "<" (__lt__ = less than) qui, quand on est sur la 4° colonne, trie cette colonne spécifique en considérant son contenu comme des chiffres, ce que ne fait pas le tri standard.
    Mais cela ne modifie en rien la façon dont on utilise le QTableWidget, qui, lui, reste celui de base.

Discussions similaires

  1. QTableWidget sort disable
    Par rabeh.ram dans le forum PyQt
    Réponses: 2
    Dernier message: 01/05/2020, 19h16
  2. StringGrid sort
    Par clovis dans le forum C++Builder
    Réponses: 4
    Dernier message: 20/10/2004, 22h46
  3. format-number()
    Par Pierre63 dans le forum XMLRAD
    Réponses: 5
    Dernier message: 11/07/2003, 18h58
  4. xsl:sort
    Par Pierre63 dans le forum XMLRAD
    Réponses: 2
    Dernier message: 03/07/2003, 13h37
  5. JBuilder 7 personnal sort à chaque save
    Par Hannouz dans le forum JBuilder
    Réponses: 4
    Dernier message: 17/12/2002, 23h53

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