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 :

QTableWidget vide quand on active son tri [QtGui]


Sujet :

PyQt Python

  1. #1
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 685
    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 685
    Points : 30 974
    Points
    30 974
    Billets dans le blog
    1
    Par défaut QTableWidget vide quand on active son tri
    Bonjour à tous

    Suite à une disussion récente à propos d'un tri de QTableWidget et d'une astucieuse solution proposée par tyrtamos, j'ai voulu appliquer cette solution à mes TableWidget.

    Le souci, c'est que la solution initiale de tyrtamos fonctionne nickel, mais quand je l'intégrais dans mes objets Qt, j'avais en retour une table à moitié vide.

    J'ai galéré pendant plusieurs jours à chercher le pourquoi du comment, et je viens de trouver. Le souci se produit quand on crée le QTableWidget avec un nombre de colonnes défini et qu'on active le sort. Si on le crée avec 0 colonnes puis qu'on positionne ensuite le nombre de colonnes, tout va bien. De même on peut le créer avec un nombre de colonnes précis, si on n'active pas le sort alors là aussi tout va bien.

    Exemple
    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
    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
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
     
    import sys
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
     
    class Fenetre(QWidget):
    	class __TableWidgetItem(QTableWidgetItem):
    		def __init__(self, sortCols, *args, **kwargs):
    			super().__init__(*args, **kwargs)
    			self.__sortCols=sortCols
     
    		def __lt__(self, other):
    			return self.__sortCols[self.column()](self.data(Qt.DisplayRole)) < self.__sortCols[self.column()](other.data(Qt.DisplayRole))
    		# __lt__()
    	# class __TableWidgetItem
     
    	__tabCols=(
    		{
    			"calc" : lambda x, row, col: ("val(%d)" % x, x),
    			"sort" : str,
    		},
    		{
    			"calc" : lambda x, row, col: ("val(%d) * row(%d)" % (x, row), x*row),
    			"sort" : str,
    		},
    		{
    			"calc" : lambda x, row, col: ("val(%d) * row(%d) + col(%d)" % (x, row, col), x*row+col),
    			"sort" : int,
    		},
    		{
    			"calc" : lambda x, row, col: ("val(%d) * col(%d)" % (x, col), x*col),
    			"sort" : int,
    		},
    		{
    			"calc" : lambda x, row, col: ("val(%d) * col(%d) + row(%d)" % (x, col, row), x*col+row),
    			"sort" : int,
    		},
    	)
    	def __init__(self, rows=10, *args, **kwargs):
    		super().__init__(*args, **kwargs)
     
    		self.resize(600, 300)
     
    		self.__tableWidget=QTableWidget(0, len(Fenetre.__tabCols), parent=self)				# Ici problème
    		self.__tableWidget.setSortingEnabled(True)
    		posit=QVBoxLayout(self)
    		posit.addWidget(self.__tableWidget, 0)
     
    		# Remplissage QTableWidget
    		self.__sortCols=tuple(x["sort"] for x in Fenetre.__tabCols)
    		self.__load(rows*2)
    		self.__load(rows)
    	# __init__()
     
    	# Remplissage table
    	def __load(self, rows):
    		self.__tableWidget.clearContents()
    		self.__tableWidget.setRowCount(rows)
    		val=0
    		for row in range(rows):
    			for col in range(len(Fenetre.__tabCols)):
    				val+=1
    				calc=Fenetre.__tabCols[col]["calc"](val, row, col)
    				item=Fenetre.__TableWidgetItem(self.__sortCols, str(calc[1]))
    				item.setToolTip(
    					"(%s = %d), sort=%s" % (
    						calc[0],
    						calc[1],
    						self.__sortCols[col],
    					)
    				)
    				#item.setData(Qt.UserRole, val)
    				self.__tableWidget.setItem(row, col, item)
    			# for
    		# for
    	# __load()
    # class Fenetre
     
    # Programme principal
    if __name__ == "__main__":
    	app=QApplication(sys.argv)
    	fen=Fenetre(rows=int(sys.argv[1])) if len(sys.argv) > 1 else Fenetre()
    	fen.show()
    	sys.exit(app.exec_())
    # if

    Le QTableWidget est créé en ligne 46 avec un nombre de colonnes précis => il apparait quasiment vide.

    Si en revanche je le crée ainsi self.__tableWidget=QTableWidget(0, 0, parent=self) et que je rajoute en dessous self.__tableWidget.setColumnCount(len(Fenetre.__tabCols)) alors plus de souci.

    Une idée du pourquoi du comment?

    Merci à tous

    PS: Je suis sous qt v5.11.3, sip v4.19.14 et pyqt v5.11.3
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 685
    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 685
    Points : 30 974
    Points
    30 974
    Billets dans le blog
    1
    Par défaut
    Bon ben je reviens sur ce fil. Après avoir discuté en privé avec tyrtamos, il semble que le souci vienne du fait que le tri est activé avant le remplissage. Je dis "il semble" car d'un côté si on active le tri après le remplissage effectivement on n'a pas de souci (c'est d'ailleurs de cette façon que je m'en suis sorti dans mon projet) mais d'autre part cela n'explique pas pourquoi l'exemple initial fonctionne dans un cas très particulier alors que le tri est quand-même activé avant le remplissage

    Petit rappel: voici le code originel, parfaitement fonctionnel
    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
    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.nbrow, self.nbcol = 5, 5
    		self.tableWidget = QtWidgets.QTableWidget(0, 0, parent=self)
    		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_())

    Mais si on remplace ce petit bloc à la ligne 38...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    self.nbrow, self.nbcol = 5, 5
    self.tableWidget = QtWidgets.QTableWidget(0, 0, parent=self)
    self.tableWidget.setRowCount(self.nbrow)
    self.tableWidget.setColumnCount(self.nbcol)

    ... par celui-ci (censé être équivalent)...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    self.nbrow, self.nbcol = 5, 5
    self.tableWidget = QtWidgets.QTableWidget(self.nbrow, self.nbcol, parent=self)
    ... là plantage complet (et nécessité d'activer le tri après le remplissage). Je mets en résolu car bon il existe une solution de contournement qui est d'activer le tri après remplisage mais cette incompréhension demeure malgré tout.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  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,

    J'ai repris mon 1er code (https://www.developpez.net/forums/d2.../#post11731890) et je confirme la situation apparemment bizarre, qui est que, AVANT le remplissage avec setItem:

    avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
            self.tableWidget = QtWidgets.QTableWidget(parent=self)
            self.tableWidget.setRowCount(self.nbrow)
            self.tableWidget.setColumnCount(self.nbcol)
     
            self.tableWidget.setSortingEnabled(True)
    ça marche (=> tableau complet), mais avec:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            self.tableWidget = QtWidgets.QTableWidget(self.nbrow, self.nbcol, parent=self)
     
            self.tableWidget.setSortingEnabled(True)
    ça ne marche pas, c'est à dire que le tableau obtenu est partiellement vide.

    L'interprétation est que une fois que le tri est activé, le remplissage avec setItem déclenche le tri qui change l'ordre des cases.

    Ce qui est anormal, c'est que ça marche dans le 1er cas! car, c'est prévu dans la doc de Qt5 pour setItem du QTableWidget (traduit en français):

    Définit l'élément pour la ligne et la colonne données à élément.
    La table prend possession de l'élément.
    Notez que si le tri est activé (voir sortingEnabled) et que la colonne est la colonne de tri actuelle, la ligne sera déplacée vers la position de tri déterminée par élément.
    Si vous souhaitez définir plusieurs éléments d'une ligne particulière (par exemple, en appelant setItem() dans une boucle), vous pouvez désactiver le tri avant de le faire et le réactiver ensuite ; cela vous permettra d'utiliser le même argument de ligne pour tous les éléments de la même ligne (c'est-à-dire que setItem() ne déplacera pas la ligne).
    La règle est donc: quand on utilise setItem et qu'on ne veut pas que le tri soit activé, il faut le désactiver avant: self.tableWidget.setSortingEnabled(False) et le réactiver après.
    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: 10
    Dernier message: 17/04/2009, 20h20
  2. Réponses: 4
    Dernier message: 22/02/2007, 15h55
  3. [formulaire] vide quand valeurs nulles
    Par gatsu07 dans le forum IHM
    Réponses: 10
    Dernier message: 02/08/2006, 14h00
  4. Réponses: 2
    Dernier message: 20/07/2006, 19h40
  5. GCC - Mon prog plante quand j'active -O1
    Par YéTeeh dans le forum Linux
    Réponses: 4
    Dernier message: 02/08/2005, 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