Question

Je suis en train d'écrire simple éditeur de propriété. J'ai généré automatiquement classe pyqt (de WorkZone dans le code ci-dessous), et je dois voir / modifier certains de ses propriétés avec PropertyEditor, avec le PropertyEditorDelegate délégué, qui utilise les éditeurs personnalisés ColorEditor, LineEditor, etc.

L'idée principale est que WorkZone sait quelles propriétés doivent être modifiées et comment, et PropertyEditor parse WorkZone, rechercher une des propriétés, et remplir QTreeWidget avec leurs valeurs.

Mais il y a un problème: délégué ne démarre pas l'édition double clic, ou « Entrée » ou lissée. Il est ajouté à la ligne droite, il peint l'article, mais c'est tout. De plus, quand je suis passé le type de conteneur PropertyEditor à QTableWidget, délégué a commencé à travailler plus approprié (mais éditeur peint dans le coin de l'écran, pas dans le tableau)!

PS. Et une autre question: est-il possible d'ajouter quelques délégués à des lignes sans avoir besoin de stocker les instances d'un ailleurs (self._delegates dans un script), il est juste UGLY. Méthode setItemDelegate accepte pointeur de déléguer, et en C ++, il obtient la propriété sur elle, mais il est PyQT pas ... À côté, il n'y a pas de problème avec setItem, par exemple.

script suivant illustre le problème:

# -*- coding: utf-8 -*-
#!/usr/bin/env python

from PyQt4 import QtCore, QtGui
import inspect


class LineEditor(QtGui.QLineEdit):


    def __init__(self, name = None, parent = None, slot = None):
        QtGui.QLineEdit.__init__(self, parent)
        self.textChanged.connect(slot)
        self.name = name

    @staticmethod
    def paintForDelegate(delegate, painter, option, index):
        QtGui.QItemDelegate.paint(delegate, painter, option, index)

    def get(self):
        return str(self.text())

    def set(self, val):
        self.setText(QtCore.QString.fromUtf8(val))

class ColorEditor(QtGui.QComboBox):


    def _populateList(self):
        for name in QtGui.QColor.colorNames():
            self.addItem(name)
            index = self.findText(name)
            self.setItemData(index, QtGui.QColor(name), QtCore.Qt.DecorationRole)

    def __init__(self, name = None, parent = None, slot = None):
        QtGui.QComboBox.__init__(self, parent)
        self._populateList()
        self.currentIndexChanged.connect(slot)
        self.name = QtCore.QString.fromUtf8(name)

    @staticmethod
    def paintForDelegate(delegate, painter, option, index):
        QtGui.QItemDelegate.paint(delegate, painter, option, index)

    def get(self):
        qColor = QtGui.QColor(self.itemData(self.currentIndex(), QtCore.Qt.DecorationRole))        
        color = ((qColor.blue() | (qColor.green() << 8)) | (qColor.red() << 16))
        return color

    def set(self, val):
        blue = (val & 255)
        green = ((val & 65280) >> 8)
        red = ((val & 16711680) >> 16)
        color = QtGui.QColor(red, green, blue)
        index = self.findData(color, QtCore.Qt.DecorationRole)
        self.setCurrentIndex(index) 

class PropertyEditorDelegate(QtGui.QItemDelegate):


    def __init__(self, object, propName, parent = None):
        QtGui.QItemDelegate.__init__(self, parent)
        self._object = object
        self._propName = propName

    def paint(self, painter, option, index):
        self._object.paintForDelegate(self._propName, self, painter, option, index)

    def createEditor(self, parent, option, index):
        return self._object.createEditor(self._propName)

    def setEditorData(self, editor, index):
        value = index.model().data(index, QtCore.Qt.EditRole)
        editor.set(value)

    def setModelData(self, editor, model, index):
        if index.column() == 0:
            model.setData(index, editor.name, QtCore.Qt.EditRole)
        else:
            model.setData(index, editor.get(), QtCore.Qt.EditRole)

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)

class PropertyEditor(QtGui.QWidget):

    def __init__(self, parent = None):
        QtGui.QWidget.__init__(self, parent)
        self._object = None
        self._delegates = []
        self._mainLayout = QtGui.QVBoxLayout()
        self._mainLayout.setContentsMargins(2, 2, 2, 2)
        self._mainLayout.setSpacing(2)
        self.setLayout(self._mainLayout)
        self._contents = QtGui.QTreeWidget()
        self._contents.setColumnCount(2)
        self._contents.currentItemChanged.connect(self.printCurrent)
        self._mainLayout.addWidget(self._contents)

    def printCurrent(self, curr, prev):
        print self._contents.currentIndex().row()
        print self._contents.currentIndex().column()
        print self._contents.itemDelegate(self._contents.currentIndex())._propName
        print self._contents.itemDelegate(self._contents.currentIndex())

    def object(self):
        return self._object

    def setObject(self, value):       
        self._object = value

        def isProperty(p):
            return isinstance(p, property)

        for (name, value) in inspect.getmembers(type(self._object), isProperty):
            if self._object.isEditable(name):
                item = QtGui.QTreeWidgetItem()
                item.setData(0, QtCore.Qt.EditRole, QtCore.QString.fromUtf8(self._object.getPropertyName(name)))
                item.setData(1, QtCore.Qt.EditRole, self._object.get(name))
                self._contents.addTopLevelItem(item)

                self._delegates.append(PropertyEditorDelegate(self._object, name, self._contents))
                index = self._contents.indexOfTopLevelItem(item)    
                self._contents.setItemDelegateForRow(index, self._delegates[index])

class WorkZone(object):


    def __init__(self):

        self._name = ''
        self.currentEditor = None
        self.red = 100
        self.green = 100
        self.blue = 100
        self._width = 1

    def _getColor(self):
        color = ((self.blue | (self.green << 8)) | (self.red << 16))
        return color

    def _setColor(self, color):
        self.blue = (color & 255)
        self.green = ((color & 65280) >> 8)
        self.red = ((color & 16711680) >> 16)

    color = property(_getColor, _setColor)

    def currentColorChanged(self, index):
        if self.currentEditor is not None:
            self.color = self.currentEditor.get()
        print self.color

    def currentNameChanged(self, newName):
        if self.currentEditor is not None:
            self.name = self.currentEditor.get()
        print self.name

    def createEditor(self, prop):
        if prop == 'color':
            self.currentEditor = ColorEditor('Color', None, self.currentColorChanged)
            self.currentEditor.set(self.color) 
            return self.currentEditor
        elif prop == 'name':
            self.currentEditor = LineEditor('Name', None, self.currentNameChanged) 
            self.currentEditor.set(self.name)
            return self.currentEditor
        else:
            return None

    def releaseEditor(self):
        self.currentEditor = None

    def isEditable(self, prop):
        if prop == 'color':
            return True
        elif prop == 'name':
            return True
        else:
            return False

    def set(self, prop, val):
        if prop == 'color':
            self.color = val
        elif prop == 'name':
            self.name = val

    def get(self, prop):
        if prop == 'color':
            return self.color
        elif prop == 'name':
            return self.name

    def getPropertyName(self, prop):
        if prop == 'color':
            return 'Color'
        elif prop == 'name':
            return 'Name'

    def paintForDelegate(self, prop, delegate, painter, option, index):
        if prop == 'color':
            ColorEditor.paintForDelegate(delegate, painter, option, index)
        elif prop == 'name':
            LineEditor.paintForDelegate(delegate, painter, option, index)

    def _setWidth(self, Width):
        self._width = Width

    def _getWidth(self):
        return self._width

    width = property(_getWidth, _setWidth)

    def _getName(self):
        return self._name

    def _setName(self, val):
        self._name = val

    name = property(_getName, _setName)



if __name__ == '__main__':

    import sys

    app = QtGui.QApplication(sys.argv)
    zone = WorkZone()
    zone.color = 0
    zone.width = 1
    propertyEditor = PropertyEditor()
    propertyEditor.setObject(zone)


    propertyEditor.show()
    sys.exit(app.exec_())
Était-ce utile?

La solution

J'ai fini par manipuler le double clic pour régler éditable, forcer l'élément en mode d'édition avec editItem (), puis le remettre. Le délégué se gère tout l'affichage et l'édition.

# In __init__:
    self.tree.itemActivated.connect(self.onDoubleClick)


def onDoubleClick(self, item, index):
    """ 
    The logic will happen in the editor delegate. This is needed to let
    the delegate run by making this editable
    """        
    item.setFlags(QtCore.Qt.ItemIsSelectable |
                  QtCore.Qt.ItemIsEnabled |
                  QtCore.Qt.ItemIsEditable)            

    # Force the item in to edit mode so the delegate picks it up
    self.tree.editItem(item, index)

    # Set the item back to not editable. The delegate will still do its
    #    job, but the read-only state will already be set when done!
    item.setFlags(QtCore.Qt.ItemIsSelectable |
                  QtCore.Qt.ItemIsEnabled)

Les premiers setFlags probablement besoin que ItemIsEditable à travailler, mais avions l'impression.

Autres conseils

Le PS.

De la documentation de PyQt

QAbstractItemView.setItemDelegate (self, QAbstractItemDelegate)

Définit le délégué de l'élément de ce point de vue et son modèle de déléguer. Ceci est utile si vous souhaitez un contrôle complet sur l'édition et l'affichage des éléments.

Tout délégué existant sera supprimé, mais pas supprimé. QAbstractItemView ne prend pas la propriété du délégué .

Attention: Vous ne devez pas partager la même instance d'un délégué entre les vues. Cela peut provoquer un comportement incorrect ou d'édition unintuitive puisque chaque vue connecté à un délégué donné peut recevoir le signal closeEditor (), et tenter d'accéder, de modifier ou fermer un éditeur qui a déjà été fermé.

La réponse est simple, comme toujours ..%) drapeaux par défaut pour les QTreeWidgetItem ne comprennent pas QtCore.Qt.ItemIsEditable.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top