models & editors in PyQt4

Discussion in 'Python' started by Skink, Aug 30, 2006.

  1. Skink

    Skink Guest

    Hi,

    I created simple property classes with editing option, but since i'm not
    too much experienced in PyQt4 i'd like to ask if i handle ColorProperty
    changing right. Any other Property has its own editor and their control
    flow is imho ok. Hovewer i'm not sure about ColorProperty.

    What i do is: in createEditor(self, parent, option, index) i call
    QtGui.QColorDialog.getColor() and return None

    What do you think? Is it Ok?

    thanks,
    skink

    #--------------------------------------------
    import sys
    from PyQt4 import QtGui, QtCore

    class PropertyDelegate(QtGui.QItemDelegate):
    def __init__(self, model):
    QtGui.QItemDelegate.__init__(self, None)
    self.model = model
    def createEditor(self, parent, option, index):
    if index.column() == 0:
    return None
    item = self.model.getItem(index)
    return item.createEditor(parent, option, index)
    def setEditorData(self, editor, index):
    item = self.model.getItem(index)
    item.setEditorData(editor, index)
    def setModelData(self, editor, model, index):
    item = self.model.getItem(index)
    item.setModelData(editor, model, index)
    # def updateEditorGeometry(self, editor, option, index):
    # editor.setGeometry(option.rect)
    def paint(self, painter, option, index):
    item = self.model.getItem(index)
    if isinstance(item, ColorProperty) and index.column() == 1:
    item.paint(painter, option, index)
    return
    QtGui.QItemDelegate.paint(self, painter, option, index)

    class SimpleModelItem:
    def __init__(self, parent=0):
    self._index = []
    self._children = []
    self._parent = parent
    if parent:
    parent._children.append(self)
    self._parent = parent
    def parent(self):
    return self._parent
    def children(self):
    return self._children
    def addIndex(self, index):
    self._index.append(index)
    def childId(self, child):
    return id(self._children[child])
    def index(self, column=0):
    return self._index[column]

    class Property(SimpleModelItem):
    def __init__(self, parent=0, name="", data=[]):
    SimpleModelItem.__init__(self, parent)
    self._data = data
    self._name = name
    def data(self, index):
    return self._data[index.column()]
    def name(self):
    return self._name
    def createEditor(self, parent, option, index):
    return None
    def setEditorData(self, editor, index):
    return
    def setModelData(self, editor, model, index):
    return

    class StringProperty(Property):
    def __init__(self, parent, name, t):
    Property.__init__(self, parent, name, [t, ""])
    def createEditor(self, parent, option, index):
    editor = QtGui.QLineEdit(parent)
    return editor
    def setEditorData(self, editor, index):
    value = index.model().getObjectData(self.name())
    editor.setText(value)
    def setModelData(self, editor, model, index):
    index.model().setObjectData(self.name(), editor.text())
    def data(self, index):
    if index.column() == 0:
    return self._data[0]
    else:
    return str(index.model().getObjectData(self.name()))
    class IntegerProperty(Property):
    def __init__(self, parent, name, t):
    Property.__init__(self, parent, name, [t, ""])
    def createEditor(self, parent, option, index):
    editor = QtGui.QSpinBox(parent)
    editor.setMaximum(256*256)
    return editor
    def setEditorData(self, editor, index):
    value = index.model().getObjectData(self.name())
    editor.setValue(value)
    def setModelData(self, editor, model, index):
    index.model().setObjectData(self.name(), editor.value())
    def data(self, index):
    if index.column() == 0:
    return self._data[0]
    else:
    return str(index.model().getObjectData(self.name()))

    class SizeProperty(Property):
    def __init__(self, parent, name, t):
    Property.__init__(self, parent, name, [t, ""])
    self.items = []
    self.items.append(IntegerProperty(self, name+":x", "x"))
    self.items.append(IntegerProperty(self, name+":y", "y"))
    self.items.append(IntegerProperty(self, name+":w", "width"))
    self.items.append(IntegerProperty(self, name+":h", "height"))

    class ColorProperty(Property):
    def __init__(self, parent, name, t):
    Property.__init__(self, parent, name, [t, ""])
    def createEditor(self, parent, option, index):
    color = QtGui.QColorDialog.getColor()
    if color.isValid():
    index.model().setObjectData(self.name(), color)
    return None
    def paint(self, painter, option, index):
    r = option.rect
    if option.state & QtGui.QStyle.State_Selected:
    painter.fillRect(r, option.palette.highlight())
    color = index.model().getObjectData(self.name())
    colorStr = color.name()
    tr = painter.boundingRect(r, QtCore.Qt.AlignLeft, colorStr)
    w = tr.width() + 4
    painter.fillRect(r.x() + 1, r.y() + 1, r.width() - 3 - w,
    r.height() - 3, QtGui.QBrush(color))
    painter.setPen(QtCore.Qt.black)
    painter.drawRect(r.x() + 1, r.y() + 1, r.width() - 3 - w,
    r.height() - 3)
    r.setLeft(r.x() + r.width() + 1 - w)
    painter.drawText(r, QtCore.Qt.AlignLeft, colorStr)

    class EnumProperty(Property):
    def __init__(self, parent, name, t, te):
    Property.__init__(self, parent, name, [t, ""])
    self.te = te
    def createEditor(self, parent, option, index):
    editor = QtGui.QComboBox(parent)
    i = 0
    for item in self.te:
    editor.addItem(item, QtCore.QVariant(i))
    i += 1
    return editor
    def setEditorData(self, editor, index):
    index = index.model().getObjectData(self.name())
    editor.setCurrentIndex(index)
    def setModelData(self, editor, model, index):
    index.model().setObjectData(self.name(), editor.currentIndex())
    def data(self, index):
    if index.column() == 0:
    return self._data[0]
    else:
    index = index.model().getObjectData(self.name())
    return self.te[index]

    class BooleanProperty(EnumProperty):
    def __init__(self, parent, name, t):
    EnumProperty.__init__(self, parent, name, t, ["False", "True"])

    #-----------------------------------------------------------------------
    class SimpleModel(QtCore.QAbstractItemModel):
    def __init__(self, root, parent=None):
    QtCore.QAbstractItemModel.__init__(self, parent)
    self.ids = {}

    self.root = root
    self.root.addIndex(QtCore.QModelIndex())
    self.ids[id(self.root)] = self.root

    self.walk(root)
    def walk(self, parent):
    row = 0
    for child in parent.children():
    _id = id(child)
    self.ids[_id] = child
    child.addIndex(self.createIndex(row, 0, _id))
    child.addIndex(self.createIndex(row, 1, _id))
    self.walk(child)
    row += 1
    def getItem(self, index):
    if not index.isValid():
    return self.root
    else:
    return self.ids[index.internalId()]

    #-----------------------------------------------------------------------
    def setObject(self, obj):
    self.obj = obj
    self.reset()
    def getObjectData(self, name):
    #print "getObjectData", name, self.obj[name]
    return self.obj[name]
    def setObjectData(self, name, value):
    #print "setObjectData", name, value
    self.obj[name] = value

    #-----------------------------------------------------------------------
    def index(self, row, column, parent):
    parentItem = self.getItem(parent)
    childItem = self.ids[parentItem.childId(row)]
    return childItem.index(column)
    def parent(self, index):
    childItem = self.getItem(index)
    parentItem = childItem.parent()
    return parentItem.index()
    def rowCount(self, parent):
    parentItem = self.getItem(parent)
    return len(parentItem.children())
    def columnCount(self, parent):
    return 2
    def data(self, index, role):
    if not index.isValid() or role != QtCore.Qt.DisplayRole:
    return QtCore.QVariant()
    item = self.getItem(index)
    return QtCore.QVariant(item.data(index))
    def flags(self, index):
    if not index.isValid():
    return QtCore.Qt.ItemIsEnabled
    else:
    return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
    | QtCore.Qt.ItemIsEditable
    def headerData(self, section, orientation, role):
    if orientation == QtCore.Qt.Horizontal and role ==
    QtCore.Qt.DisplayRole:
    if section == 0:
    return QtCore.QVariant("Name")
    else:
    return QtCore.QVariant("Value")
    return QtCore.QVariant()

    objAData = {
    "width": 6, "size:x": 10, "size:y": 15, "size:w": 20, "size:h": 25,
    "frameType": 0, "visible": 1, "color": QtGui.QColor(QtCore.Qt.red),
    "name": "foobar A"
    }
    objBData = {
    "width": 66, "size:x": 100, "size:y": 150, "size:w": 200, "size:h":
    250,
    "frameType": 1, "visible": 0, "color": QtGui.QColor(QtCore.Qt.green),
    "name": "foobar B"
    }
    objCData = {
    "width": 666, "size:x": 1000, "size:y": 1500, "size:w": 2000,
    "size:h": 2500,
    "frameType": 2, "visible": 1, "color": QtGui.QColor(QtCore.Qt.blue),
    "name": "foobar C"
    }

    root = Property()
    newItem = StringProperty(root, "name", "Name")
    newItem = IntegerProperty(root, "width", "Item Width")
    newItem = ColorProperty(root, "color", "Background Color")
    newItem = SizeProperty(root, "size", "Item Size")
    newItem = EnumProperty(root, "frameType", "Frame Type", ["Solid",
    "Dashed", "None"])
    newItem = BooleanProperty(root, "visible", "Visibility")

    class Widget(QtGui.QWidget):
    def __init__(self, parent=None):
    QtGui.QWidget.__init__(self, parent)
    mainLayout = QtGui.QVBoxLayout()

    self.treeView = QtGui.QTreeView()

    self.treeView.setEditTriggers(QtGui.QAbstractItemView.SelectedClicked)
    self.model = SimpleModel(root)
    self.delegate = PropertyDelegate(self.model)
    self.treeView.setItemDelegate(self.delegate)
    self.model.setObject(objAData)
    self.treeView.setModel(self.model)
    mainLayout.addWidget(self.treeView)
    b1 = QtGui.QPushButton("Object A")
    self.connect(b1, QtCore.SIGNAL("clicked()"), self.objAClicked)
    mainLayout.addWidget(b1)
    b2 = QtGui.QPushButton("Object B")
    self.connect(b2, QtCore.SIGNAL("clicked()"), self.objBClicked)
    mainLayout.addWidget(b2)
    b3 = QtGui.QPushButton("Object C")
    self.connect(b3, QtCore.SIGNAL("clicked()"), self.objCClicked)
    mainLayout.addWidget(b3)
    self.setLayout(mainLayout)
    def objAClicked(self):
    self.model.setObject(objAData)
    def objBClicked(self):
    self.model.setObject(objBData)
    def objCClicked(self):
    self.model.setObject(objCData)


    if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    widget = Widget()
    widget.show()
    sys.exit(app.exec_())
    #--------------------------------------------
    Skink, Aug 30, 2006
    #1
    1. Advertising

  2. Skink

    David Boddie Guest

    Skink wrote:

    > I created simple property classes with editing option, but since i'm not
    > too much experienced in PyQt4 i'd like to ask if i handle ColorProperty
    > changing right. Any other Property has its own editor and their control
    > flow is imho ok. Hovewer i'm not sure about ColorProperty.
    >
    > What i do is: in createEditor(self, parent, option, index) i call
    > QtGui.QColorDialog.getColor() and return None
    >
    > What do you think? Is it Ok?


    It should be OK - it shouldn't crash, anyway. It depends on the view
    doing the right thing when it finds that it hasn't received an editor
    widget.

    You could create an empty placeholder widget in the createEditor()
    method, call QColorDialog.getColor() with the existing color from the
    model in setEditorData(), record the color returned by the dialog in
    some internal instance variable, and finally set the data in the model
    when setModelData() is called:

    class ColorProperty(Property):
    ...
    def createEditor(self, parent, option, index):
    return QtGui.QWidget(parent)
    def setEditorData(self, editor, index):
    self.color = QtGui.QColorDialog.getColor(
    index.model().getObjectData(self.name()))
    def setModelData(self, editor, model, index):
    if self.color.isValid():
    index.model().setObjectData(self.name(), self.color)
    ...

    I find it strange that you have to triple-click to edit any of the
    items in your example. Do you see the same behaviour?

    David
    David Boddie, Aug 30, 2006
    #2
    1. Advertising

  3. Skink

    Skink Guest

    David Boddie wrote:
    >
    > It should be OK - it shouldn't crash, anyway. It depends on the view
    > doing the right thing when it finds that it hasn't received an editor
    > widget.
    >
    > You could create an empty placeholder widget in the createEditor()
    > method, call QColorDialog.getColor() with the existing color from the
    > model in setEditorData(), record the color returned by the dialog in
    > some internal instance variable, and finally set the data in the model
    > when setModelData() is called:
    >
    > class ColorProperty(Property):
    > ...
    > def createEditor(self, parent, option, index):
    > return QtGui.QWidget(parent)
    > def setEditorData(self, editor, index):
    > self.color = QtGui.QColorDialog.getColor(
    > index.model().getObjectData(self.name()))
    > def setModelData(self, editor, model, index):
    > if self.color.isValid():
    > index.model().setObjectData(self.name(), self.color)


    thanks for tip, i'll check it how it works.

    > ...
    >
    > I find it strange that you have to triple-click to edit any of the
    > items in your example. Do you see the same behaviour?

    oh, this is default Qt behavoiur: first click selects row, second select
    editor (for ColorProperty, IntProperty & StringProperty you can now
    change the value) but third click is required only for properties w/
    QCombobox editor (EnumProperty & BooleanProperty) ...

    skink

    >
    > David
    >
    Skink, Aug 30, 2006
    #3
  4. Skink

    David Boddie Guest

    Skink wrote:
    > David Boddie wrote:


    > > I find it strange that you have to triple-click to edit any of the
    > > items in your example. Do you see the same behaviour?


    > oh, this is default Qt behavoiur: first click selects row, second select
    > editor (for ColorProperty, IntProperty & StringProperty you can now
    > change the value) but third click is required only for properties w/
    > QCombobox editor (EnumProperty & BooleanProperty) ...


    It seemed that, even if the row was already selected, it took more than
    a double click to start editing. I'll have to take another look at it.

    David
    David Boddie, Aug 30, 2006
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. vinjvinj
    Replies:
    15
    Views:
    562
    Jeremy Sanders
    Nov 10, 2005
  2. Jean-Paul Calderone
    Replies:
    0
    Views:
    424
    Jean-Paul Calderone
    Nov 7, 2005
  3. Harshad

    Drag and Drop with PyQt4

    Harshad, Aug 25, 2006, in forum: Python
    Replies:
    2
    Views:
    1,212
    Harshad
    Aug 26, 2006
  4. wgw
    Replies:
    1
    Views:
    454
  5. David Heinemeier Hansson
    Replies:
    0
    Views:
    218
    David Heinemeier Hansson
    Dec 23, 2004
Loading...

Share This Page