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 :

QTableView et les délégués


Sujet :

PyQt Python

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2009
    Messages : 7
    Par défaut QTableView et les délégués
    En lisant la doc de la tableview, j'ai cru comprendre qu'on pouvait remplacer le champ d'édition d'une cellule par n'importe quel widget.
    Dans mon cas, j'aimerais que la première colonne soit de type QcheckBox, et la 3e de type QComboBox.

    Est-ce que quelqu'un pourrait m'aiguiller sur les méthodes à suivre, parce que pour le moment, je n'arrive à rien ...

    Merci beaucoup

    Julien

  2. #2
    Membre émérite
    Homme Profil pro
    Inscrit en
    Janvier 2006
    Messages
    491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Corse (Corse)

    Informations forums :
    Inscription : Janvier 2006
    Messages : 491
    Par défaut
    un code de ce style:
    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
    class MonDelegate(QItemDelegate):
        def __init__(self,parent=None):
            super(MonDelegate,self).__init__(parent)
     
        def createEditor(self,parent,option,index):
            if index.column()==0:
               ma_check=QCheckBox(parent)
               return  ma_check
     
            if index.column()==2:
               ma_combo=QComboBox(parent)
               ma_combo.addItems(['','item1','item2?....'])
                return ma_combo
           else :
              return QItemDelegate.createEditor(self,parent,option,index)

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2009
    Messages : 7
    Par défaut
    Merci !
    Cela dit, est-il possible que les cellules conservent l'affichage des widgets quand elles ne sont pas selectionnées ?

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    99
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 99
    Par défaut
    Salut,

    Dans l'idée, xavier-pierre t'as proposé quelque chose qui peut te mettre sur la voie. Mais d'après ce que tu as l'air de vouloir, il va te falloir un peu plus de boulot pour arriver au resultat.

    Il faut par exemple re-implémenter paint() si tu veux avoir le visuel d'une CheckBox en dehors de l'édition. Sinon ton model ne montrera que la data en tant que string.

    Il faut aussi lier ta ComboBox à ton QAbstractModel pour que l'édition aille bien sauvegarder les donner la ou tu veux.

    Je suis tombé il y a quelques temps sur un blog assez bien foutu sur le même sujet que toi. Le voici: http://da-crystal.net/GCMS/blog/checkboxlist-in-qt C'est du C++, mais ca se converti très bien en python.


    Voici l'exemple que j'utilise et qui manipule dans un TableView, en colonne 0 une CheckBox, et en colonne 2 une ProgressBar.
    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
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
     
    class RepositoryTableDelegate(QtGui.QItemDelegate):
        '''
        Class that defines and implement the visual customization of the table
            view to show check boxes and progress bars.
        
        @ingroup DM
        '''
        def __init__(self, owner):
            '''
            Class constructor
            
            @param[in] owner The owner of this widget.
            '''
            QtGui.QItemDelegate.__init__(self, owner)
     
        def paint(self, painter, option, index):
            '''
            Method to draw the model.
            
            @param[in] painter The painter to use to draw.
            @param[in] option The QStyleOptionViewItem defining the needed object option.
            @param[in] index The
            '''
            column = index.column()
            if column == 0:
                # Get item data
                value = index.data(QtCore.Qt.DisplayRole).toBool()
     
                # fill style options with item data
                style = QtGui.QApplication.style()
                opt = QtGui.QStyleOptionButton()
                opt.state |= QtGui.QStyle.State_On if value else QtGui.QStyle.State_Off
                opt.state |= QtGui.QStyle.State_Enabled
                opt.text = ""
                opt.rect = option.rect
     
                # draw item data as CheckBox
                style.drawControl(QtGui.QStyle.CE_CheckBox, opt, painter)
                return
     
            elif column == 2:
                # Get the % number of loaded revisions.
                value = index.data(QtCore.Qt.DisplayRole)
                value,_ = value.toInt()
     
                # fill style options with item data
                style = QtGui.QApplication.style()
                opt = QtGui.QStyleOptionProgressBarV2()
                opt.maximum = 100
                opt.progress = value
                opt.rect = option.rect
                opt.textVisible = False
                opt.text = str(value)
     
                # draw item data as CheckBox
                style.drawControl(QtGui.QStyle.CE_ProgressBar, opt, painter)
                return
     
            QtGui.QItemDelegate.paint(self, painter, option, index)
     
        def createEditor(self, parent, option, index):
            column = index.column()
            if column == 0:
                # create check box as our editor.
                editor = QtGui.QCheckBox(parent)
                return editor
     
            elif column == 2:
                # create the ProgressBar as our editor.
                editor = QtGui.QProgressBar(parent)
                return editor
     
            return QtGui.QAbstractItemDelegate.createEditor(self, parent, option, index)
     
        def setEditorData(self, editor, index):
            column = index.column()
            if column == 0:
                # set editor data
                value = index.data(QtCore.Qt.DisplayRole).toBool()
                editor.setChecked(value)
                return
     
            elif column == 2:
                value,_ = index.data(QtCore.Qt.DisplayRole).toInt()
                editor.setValue(value)
                return
     
            QtGui.QAbstractItemDelegate.setEditorData(self, editor, index)
     
        def updateEditorGeometry(self, editor, option, index):
            editor.setGeometry(option.rect)
    Je suis désolé, je viens de me rendre compte que mon code n'est pas très bien commenté. Shame on me. Enfin te voici de quoi travailler.
    J'éditerai mon post avec les commentaire adéquates des que possible.

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2009
    Messages : 7
    Par défaut
    Merci beaucoup ! C'est exactement ça, j'ai de quoi potasser ...

    Par contre, je viens d'implementer rapidement ton code sur une table view basique, et je ne peux pas cocher les Checkboxes, elles restent décochées tout le temps. Est-ce que tu as le même comportement ?

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    99
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 99
    Par défaut
    Il doit falloir que tu 'actives' l'éditeur. Pour cela il faut changer une option dans le QTableView que tu utilises.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    # Set the event behavior.
    TableView.setEditTriggers(QtGui.QAbstractItemView.CurrentChanged)
    TableView.viewport().installEventFilter(TableView)
    Avec cela ca devrait aller mieux. Mais la honnêtement on arrive a mes limites de compréhension de la mécanique de Qt, je n'ai pas eu le temps d'approfondir le pourquoi du comment de ces 2 lignes. Je me suis contenté de reprendre ce que j'avais vu sur le blog cité dans mon 1er post.

  7. #7
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut
    Intéressant tout cela... bolbacool, serait-il possible de voir ton code au complet ?

    Je cherche de mon côté à mettre des lineedit muni d'une fonctionnalité de coloration syntaxique dans un TableView.

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2009
    Messages : 7
    Par défaut
    Voici le code d'une implémentation basique :

    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
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
     
    import sys
    from PyQt4 import QtCore, QtGui
     
    class RepositoryTableDelegate(QtGui.QItemDelegate):
        '''
        Class that defines and implement the visual customization of the table
            view to show check boxes and progress bars.
        
        @ingroup DM
        '''
        def __init__(self, owner):
            '''
            Class constructor
            
            @param[in] owner The owner of this widget.
            '''
            QtGui.QItemDelegate.__init__(self, owner)
     
        def paint(self, painter, option, index):
            '''
            Method to draw the model.
            
            @param[in] painter The painter to use to draw.
            @param[in] option The QStyleOptionViewItem defining the needed object option.
            @param[in] index The
            '''
            column = index.column()
            if column == 0:
                # Get item data
                value = index.data(QtCore.Qt.DisplayRole).toBool()
     
                # fill style options with item data
                style = QtGui.QApplication.style()
                opt = QtGui.QStyleOptionButton()
                opt.state |= QtGui.QStyle.State_On if value else QtGui.QStyle.State_Off
                opt.state |= QtGui.QStyle.State_Enabled
                opt.text = ""
                opt.rect = option.rect
     
                # draw item data as CheckBox
                style.drawControl(QtGui.QStyle.CE_CheckBox, opt, painter)
                return
     
            elif column == 2:
                # Get the % number of loaded revisions.
                value = index.data(QtCore.Qt.DisplayRole)
                value,_ = value.toInt()
     
                # fill style options with item data
                style = QtGui.QApplication.style()
                opt = QtGui.QStyleOptionProgressBarV2()
                opt.maximum = 100
                opt.progress = value
                opt.rect = option.rect
                opt.textVisible = False
                opt.text = str(value)
     
                # draw item data as CheckBox
                style.drawControl(QtGui.QStyle.CE_ProgressBar, opt, painter)
                return
     
            QtGui.QItemDelegate.paint(self, painter, option, index)
     
        def createEditor(self, parent, option, index):
            column = index.column()
            if column == 0:
                # create check box as our editor.
                editor = QtGui.QCheckBox(parent)
                return editor
     
            elif column == 2:
                # create the ProgressBar as our editor.
                editor = QtGui.QProgressBar(parent)
                return editor
     
            return QtGui.QAbstractItemDelegate.createEditor(self, parent, option, index)
     
        def setEditorData(self, editor, index):
            column = index.column()
            if column == 0:
                # set editor data
                value = index.data(QtCore.Qt.DisplayRole).toBool()
                editor.setChecked(value)
                return
     
            elif column == 2:
                value,_ = index.data(QtCore.Qt.DisplayRole).toInt()
                editor.setValue(value)
                return
     
            QtGui.QAbstractItemDelegate.setEditorData(self, editor, index)
     
        def updateEditorGeometry(self, editor, option, index):
            editor.setGeometry(option.rect)
     
    if __name__ == "__main__":
    	app = QtGui.QApplication(sys.argv)
    	app.setStyle(QtGui.QStyleFactory.create("Plastique"))
     
    	tableView = QtGui.QTableView()
     
    	model = QtGui.QStandardItemModel(2, 4)
    	tableView.setModel(model)
    	tableView.setEditTriggers(QtGui.QAbstractItemView.CurrentChanged)
    	tableView.viewport().installEventFilter(tableView)
     
    	delegate = RepositoryTableDelegate(tableView)
    	tableView.setItemDelegate(delegate)
     
    	tableView.setWindowTitle("Items Delegate")
    	tableView.show()
    	sys.exit(app.exec_())
    Par contre, il y a des moments où l'on ne peut pas cocher des cases, et d'autres où l'on peut ... Etrange

  9. #9
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut
    Merci beaucoup pour ce joli cadeau...

  10. #10
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2009
    Messages : 7
    Par défaut
    Après avoir étudié le code de shadowman, je l'ai adapté à ma sauce.
    J'ai aussi découvert une fonction setItemDelegateForColumn qui permet de simplifier le code, et de créer des delegates "standard", puis de les appliquer par colonnes.

    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
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
     
    import sys
    from PyQt4 import QtCore, QtGui
     
    class CheckBoxDelegate(QtGui.QItemDelegate):
     
    	def __init__(self, owner):
    		QtGui.QItemDelegate.__init__(self, owner)
     
    	def paint(self, painter, option, index):
    		# Get item data
    		value = index.data(QtCore.Qt.DisplayRole).toBool()
     
    		# fill style options with item data
    		style = QtGui.QApplication.style()
    		opt = QtGui.QStyleOptionButton()
    		opt.state |= QtGui.QStyle.State_On if value else QtGui.QStyle.State_Off
    		opt.state |= QtGui.QStyle.State_Enabled
    		opt.text = ""
    		opt.rect = option.rect
     
    		# draw item data as CheckBox
    		style.drawControl(QtGui.QStyle.CE_CheckBox, opt, painter)
    		#QtGui.QItemDelegate.paint(self, painter, option, index)
     
    	def createEditor(self, parent, option, index):
    		# create check box as our editor.
    		editor = QtGui.QCheckBox(parent)
    		editor.installEventFilter(self)
    		editor.setGeometry(4,4,16,16)
     
    		self.connect (editor, QtCore.SIGNAL('clicked()'), self.toggleActive)
     
    		return editor
     
    	def setEditorData(self, editor, index):
    		# set editor data
    		value = index.data(QtCore.Qt.DisplayRole).toBool()
    		editor.setChecked(value)
     
    	def setModelData(self,editor,model,index):
    		value = editor.checkState()
    		model.setData(index, QtCore.QVariant(value))
     
    	def updateEditorGeometry(self, editor, option, index):
    		editor.setGeometry(option.rect)
     
    	def toggleActive(self):
    		print "toggled"
     
    class ComboBoxDelegate(QtGui.QItemDelegate):
     
    	def __init__(self, owner, itemslist):
    		QtGui.QItemDelegate.__init__(self, owner)
    		self.itemslist = itemslist
     
    	def paint(self, painter, option, index):		
    		# Get Item Data
    		value = index.data(QtCore.Qt.DisplayRole).toInt()[0]
    		# fill style options with item data
    		style = QtGui.QApplication.style()
    		opt = QtGui.QStyleOptionComboBox()
    		opt.currentText = str(self.itemslist[value])
    		opt.rect = option.rect
     
    		# draw item data as ComboBox
    		style.drawComplexControl(QtGui.QStyle.CC_ComboBox, opt, painter)
     
    	def createEditor(self, parent, option, index):
    		# create the ProgressBar as our editor.
    		editor = QtGui.QComboBox(parent)
    		editor.addItems(self.itemslist)
    		editor.setCurrentIndex(0)
    		editor.installEventFilter(self)			
    		return editor
     
    	def setEditorData(self, editor, index):
    		value = index.data(QtCore.Qt.DisplayRole).toInt()[0]
    		editor.setCurrentIndex(value)
     
    	def setModelData(self,editor,model,index):
    		value = editor.currentIndex()
    		model.setData(index, QtCore.QVariant(value))
     
    	def updateEditorGeometry(self, editor, option, index):
    		editor.setGeometry(option.rect)
     
    class VarTableView(QtGui.QTableView):
    	def __init__(self):
    		QtGui.QTableView.__init__(self)
    		self.horizontalHeader().setStretchLastSection(True)
    		self.mdl = QtGui.QStandardItemModel(2, 5)
    		self.setModel(self.mdl)
     
    		self.setEditTriggers(QtGui.QAbstractItemView.CurrentChanged)
     
    		self.setItemDelegateForColumn(0,CheckBoxDelegate(self))
    		self.setItemDelegateForColumn(2,ComboBoxDelegate(self, ['item1','item2', 'item3']))
    		self.setItemDelegateForColumn(3,ComboBoxDelegate(self, ['test1','test2', 'test3', 'test4', 'test5']))	
     
    		self.setColumnWidth(0, 16)
    		self.setColumnWidth(2, 64)
    		self.setColumnWidth(3, 64)
     
    		self.setWindowTitle("Variables Table View")
     
    if __name__ == "__main__":
    	app = QtGui.QApplication(sys.argv)
    	app.setStyle(QtGui.QStyleFactory.create("Plastique"))
     
    	tableView = VarTableView()
    	for row in range (2):
    		for column in range (5):
    			index = tableView.mdl.index(row, column, QtCore.QModelIndex())
    			if column == 0:
    				tableView.mdl.setData(index,QtCore.QVariant(True))
    			elif column == 2:
    				tableView.mdl.setData(index,QtCore.QVariant(0))
    			else:
    				tableView.mdl.setData(index,QtCore.QVariant("Text"))
     
    	tableView.setGeometry(500,500,500,200)
    	tableView.show()
    	sys.exit(app.exec_())
    Quelques problèmes subsistent :
    - Dans le cas des combobox, l'item selectionné ne reste pas affiché. Je ne comprends pas trop, parce que dans la doc, ils expliquent que c'est la variable currentText qui sera affiché, et dans mon cas elle est bien définie. Bizarre ...
    - Un autre problème est que, lorsque l'on définie un itemDelegate pour une colonne, il faut que le modèle reçoive une valeur par défaut (un booleen pour les checkbox, et un integer pour les combobox). Pour le moment je le fais après avoir créé ma tableview, mais j'aimerais pouvoir l'automatiser, et je ne sais pas trop où ...
    - Dans tous les cas, il faut cliquer 2 fois sur chaque itemDelegate pour l'éditer. Ca dois être un problème de fucus, mais je ne vois pas comment changer ça
    - La checkbox est censée me servir à activer ou non une ligne. J'ai connecté le signal clicked du checkbox a une fonction toggleActive, mais je ne sais pas comment récupérer a ligne du checkbox cliqué.

    Ca avance, mais ça n'est pas encore ça ... Des idées ?

  11. #11
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    99
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 99
    Par défaut
    Salut Bolbacool,

    Je n'ai pas de réponse pour toi en ce qui concerne la combo box qui ne s'affiche pas en dehors de l'édition.

    Mais je pense savoir pourquoi il faut cliquer 2 fois pour pouvoir éditer un élément. Quand le delegate n'est pas en mode d'édition, il faut cliquer une fois pour créer l'éditeur et entrer dans le mode d'édition.
    Ensuite il faut a nouveau cliquer sur le checkbox pour changer la valeur. Il n'y a pas moyen (à ma connaissance) de ne pas avoir ce clique nécessaire a entrer en mode d'édition.

    Ou alors il faudrait trouver un moyen d'être en permanence en édition... mais cela serait a la fois gourmand en mémoire et en CPU.

    Au passage, merci pour l'info sur les delegate par colonne. Je ne connaissais pas et c'est vrai que ca fait un code plus clair.

Discussions similaires

  1. Apostille au MVC : les délégués
    Par dourouc05 dans le forum Qt
    Réponses: 0
    Dernier message: 05/08/2011, 15h28
  2. Réponses: 0
    Dernier message: 29/12/2010, 00h06
  3. Comment enlever tous les délégués ?
    Par Papy214 dans le forum Windows Forms
    Réponses: 3
    Dernier message: 24/10/2008, 12h21
  4. [C#] [WinForms] Les délégués dans la souffrance
    Par stailer dans le forum Windows Forms
    Réponses: 2
    Dernier message: 08/10/2004, 12h32

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