[PyQt] QListView and QItemDelegate editor widget question

Jack Trades jacktradespublic at gmail.com
Sun Jan 16 20:24:05 GMT 2011


I'm trying to make a list where selecting an item opens an editing
widget of arbitrary size.  Here's a simple example.

List with nothing selected...
___________________
Item 1
___________________
Item 2
___________________
Item 3
___________________
Item n
___________________


List with an item selected...

___________________
Item 1
___________________
Item 2

Label:  |___________|
Label:  |___________|
_________________
|  Calendar
|  or other widget
|_________________
___________________
Item 3
___________________
Item n
___________________


I modified the spinbox example and got this...
___________________
Item 1
___________________


Big spinbox here

___________________
Item n
___________________


The spinbox widget simply covers up entries 3 through n.

I'm assuming that it has something to do with the sizeHint and paint
methods of the ItemDelegate.  But I'm not sure.  Is this even possible
with a listview or am I wasting my time?

The shortest version I could make of my code is below.  Basically it
is a copy of the spinbox example with the QStandardItemModel replaced
with a QAbstractListModel and the QTableView replaced with a
QListView.  Sorry if there's some ugly bits in there I've been trying
to figure this out for days and I'm pretty much just fumbling around
in the dark by now.

import sip
sip.setapi('QVariant', 2)

from PyQt4 import QtCore, QtGui


class SpinBoxDelegate(QtGui.QItemDelegate):
  def createEditor(self, parent, option, index):
    editor = QtGui.QSpinBox(parent)
    editor.setMinimumHeight(100)
    return editor

  def paint(self, painter, option, index):
    super(SpinBoxDelegate, self).paint(painter, option, index)

  def sizeHint(self, option, index):
    if option.state & QtGui.QStyle.State_Enabled:
      editor = self.createEditor(None, option, index)
      return editor.sizeHint()
    else:
      return index.data().sizeHint()

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

  def setModelData(self, spinBox, model, index):
    spinBox.interpretText()
    value = spinBox.value()
    model.setData(index, value, QtCore.Qt.EditRole)

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



class MyListModel(QtCore.QAbstractListModel):
  def __init__(self, parent=None):
    QtCore.QAbstractListModel.__init__(self, parent)
    self.listdata = [1,2,3,5,8,13]

  def rowCount(self, parent=QtCore.QModelIndex()):
    return len(self.listdata)

  def data(self, index, role):
    if not index.isValid():
      print "index not valid"
    elif role == QtCore.Qt.DisplayRole:
      return self.listdata[index.row()]
    elif role == QtCore.Qt.EditRole:
      return self.listdata[index.row()]
    else:
      return None

  def setData(self, index, value, role):
    if role == QtCore.Qt.EditRole:
      self.listdata[index.row()] = value

  def flags(self, index):
    if not index.isValid():
      return QtCore.Qt.NoItemFlags

    return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled

  def addItems(self, data, position):
    self.beginInsertRows(QtCore.QModelIndex(), position, position)
    self.listdata.append(data)
    self.endInsertRows()


if __name__ == '__main__':

  import sys

  app = QtGui.QApplication(sys.argv)

  model = MyListModel()
  listView = QtGui.QListView()
  listView.setModel(model)

  delegate = SpinBoxDelegate()
  listView.setItemDelegate(delegate)

  listView.setWindowTitle("Spin Box Delegate")
  listView.show()
  sys.exit(app.exec_())


More information about the PyQt mailing list