[PyQt] QAbstractItemModel.setData() and emit

Tom Brown brown at esteem.com
Thu Jul 19 20:54:25 BST 2007


On Thursday 19 July 2007 10:41, Andreas Pakulat wrote:
> On 19.07.07 09:14:20, Tom Brown wrote:
> > On Wednesday 18 July 2007 15:40, Andreas Pakulat wrote:
> > > On 18.07.07 14:58:11, Tom Brown wrote:
> > > > Hi,
> > > >
> > > > I am using PyQt4 with Qt 4.2.3. I have subclassed QAbstractItemModel
> > > > to create a custom model for a custom combobox. I have overridden the
> > > > setData() method and keep getting this error:
> > > >
> > > > TypeError: invalid result type from ECBModel.setData()
> > > >
> > > > When I remove the call to emit(), the error goes away. Here is my
> > > > setData() method:
> > >
> > > You don't need to emit dataChanged in setData, you only need to emit
> > > that signal if you change data in custom methods.
> >
> > The documentation says you need to emit dataChanged() if you reimplement
> > the setData() method.
> >
> > "Note that the dataChanged() signal must be emitted explicitly when
> > reimplementing this function."
>
> Hmm, my Qt4.3 docs only say it should be emitted, not that it has to be
> emitted. Anyway, basically you're right and I was wrong (looks like my
> last model impl. is quite some time ago)
>
> > > Also note: setData shouldn't alter the number of rows or columns in the
> > > model, it should only change the data of an existing "cell". If you
> > > want to add a row/column you should use insertRows/Columns (and
> > > eventually re-implement them).
> >
> > Well, I reimplemented a few required methods like index() and parent().
> > The error stopped showing up. However, the combobox never shows a value
> > even though there are items in the list. Any ideas on that?
>
> Not without some example code. Up-to-date PyQt snapshots contain a
> python port of the ModelTest from Qt Labs, it can be used to test wether
> your model conforms to the assumptions that views make about it.

Here's my model. I am running queries against a PostgreSQL database. I'll try 
out the ModelTest. Thanks.

class ECBModel(QAbstractItemModel):
  def __init__(self, dbInfo, sql, parent=None):
    QAbstractItemModel.__init__(self, parent)
    self.dbInfo = dbInfo
    self.sql = sql
    self.insertSQL = None
    self.queryData = []
    self.sequence = None
    self.refresh()

  def columnCount(self, parent):
    return 2

  def currentID(self, currentText):
    for row in self.queryData:
      if row[1] == currentText:
        return row[0]
    return None

  def data(self, index, role):
    if not index.isValid():
      return QVariant()
    if role != Qt.DisplayRole:
      return QVariant()
    if not self.queryData:
      return QVariant()
    if not (index.row() < len(self.queryData)):
      return QVariant()
    return QVariant(self.queryData[index.row()][index.column()])

  def flags(self, index):
    return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable

  def getIDFromText(self, text):
    return self.currentID(text)

  def index(self, row, column, parent):
    data = self.queryData[row][column]
    return self.createIndex(row, column, data)

  def insertRows(self, row, count, parent):
    self.beginInsertRows(parent, row - 1, row - 1)
    self.queryData.insert(row, [0, ''])
    self.endInsertRows()
    return True

  def insertRecord(self, value):
    if self.insertSQL:
      connection, cursor = getPgCursor(self.dbInfo)
      try:
        try:
          id = getNextVal(cursor, self.sequence)
          sql = self.insertSQL % (id, value)
          cursor.execute(sql)
          connection.commit()
        finally:
          connection.close()
      except:
        return (0, '')
      return id, value
    return (0, '')

  def parent(self, index):
    return QModelIndex()

  def refresh(self):
    self.queryData = []
    connection, cursor = getPgCursor(self.dbInfo)
    try:
      cursor.execute(self.sql)
      rows = cursor.fetchall()
      for row in rows:
        self.queryData.append([row[0], row[1]])
      connection.commit()
    finally:
      connection.close()

  def rowCount(self, parent):
    return len(self.queryData)

  def setData(self, index, value, role):
    id, value = self.insertRecord(str(value.toString()))
    if id:
      data = index.internalPointer()
      data[0] = id
      data[1] = value
      self.emit(SIGNAL('dataChanged(const QModelIndex &, '
        'const QModelIndex &)'), index, index)
      return True
    return False

  def setID(self, id):
    rowCount = 0
    for row in self.queryData:
      if row[0] == id:
        return rowCount
      rowCount += 1
    return None

  def setInsertSQL(self, sql):
    self.insertSQL = sql



More information about the PyQt mailing list