Devuelva un objeto en un rol en Python y obtenga una referencia de otro objeto en QML

Estoy escribiendo un cliente de Twitter. Implementé TweetItem y TweetModel . El problema es que hay un rol en TweetItem llamado original . Quiero que apunte al tweet original.

Actualización: Hubo algún error tipográfico en mi código. Ahora los he arreglado.

 import sys from PyQt4 import QtCore, QtGui, QtDeclarative class TweetModel(QtCore.QAbstractListModel): def __init__(self, prototype, parent=None): QtCore.QAbstractListModel.__init__(self, parent) self.setRoleNames(prototype.roleNames()) self.tweets = [] def appendRow(self, item): self.tweets.append(item) def rowCount(self, parent=QtCore.QModelIndex()): return len(self.tweets) def data(self, index, role): return self.tweets[index.row()].data(role) class TweetItem(QtCore.QAbstractItemModel): def __init__(self, id=None, original=None, parent=None): QtCore.QAbstractItemModel.__init__(self, parent) self.idRole = QtCore.Qt.UserRole + 1 # More Roles self.originalRole = QtCore.Qt.UserRole + 6 self.id = id self.original = original def roleNames(self): names = {} names[self.idRole] = "id" names[self.originalRole] = "original" return names def data(self, role): if role == self.idRole: return self.id elif role == self.originalRole: # self.original ==  return self.original else: return None if __name__ == "__main__": model = TweetModel(TweetItem()) item = TweetItem("0001", None, model) model.appendRow(TweetItem("0002", item, model)) App = QtGui.QApplication(sys.argv) view = QtDeclarative.QDeclarativeView() view.rootContext().setContextProperty("mymodel", model) view.setSource(QtCore.QUrl.fromLocalFile("main.qml")) view.show() App.exec_() 

Pero no puedo usarlo en QML. Obtengo un valor undefined .

 import QtQuick 1.0 Rectangle { width: 360 height: 360 ListView { anchors.fill: parent model: mymodel // original.id == undefined delegate: Component { Text { text: id + " " + original.id } } } } 

Entonces, ¿es posible devolver un objeto en un role y usarlo?

Como sugirió dant3, use QObject con propiedades.

Aquí hay un ejemplo de cómo hacerlo:

 import sys from PyQt4 import QtCore, QtGui, QtDeclarative from PyQt4.QtCore import pyqtProperty, pyqtSignal, QObject class TweetModel(QtCore.QAbstractListModel): def __init__(self, prototype, parent=None): QtCore.QAbstractListModel.__init__(self, parent) self.setRoleNames(prototype.roles) self.tweets = [] def appendRow(self, item): self.tweets.append(item) def rowCount(self, parent=QtCore.QModelIndex()): return len(self.tweets) def data(self, index, role): return self.tweets[index.row()].data(role) class TweetItem(QObject): roles = { QtCore.Qt.UserRole + 1: 'id', QtCore.Qt.UserRole + 6: 'original', } id_changed = pyqtSignal() def __init__(self, id=None, original=None, parent=None): QObject.__init__(self, parent=parent) self._data = {'original': original} self.id = id def data(self, key): return self._data[self.roles[key]] @pyqtProperty(str, notify=id_changed) def id(self): return self._data['id'] @id.setter def id(self, value): if self._data.get('id') != value: self._data['id'] = value self.id_changed.emit() if __name__ == "__main__": model = TweetModel(TweetItem) item = TweetItem("0001", None, model) model.appendRow(TweetItem("0002", item, model)) App = QtGui.QApplication(sys.argv) view = QtDeclarative.QDeclarativeView() view.rootContext().setContextProperty("mymodel", model) view.setSource(QtCore.QUrl.fromLocalFile("main.qml")) view.show() App.exec_() 

El archivo QML sigue siendo el mismo.

No hice una propiedad original , ya que la obtienes como datos de modelo, pero puedes hacerlo de la misma manera que id .

Supongo que no está definido al acceder a su objeto TweetItem , sino al intentar obtener una identificación.

En su apariencia, su implementación de QAbstractItemModel en TweetItem es simplemente incorrecta. Su método de datos no acepta ningún índice, ni implementa rowCount. Consulte la documentación de Qt sobre cómo implementar la interfaz QAbstractItemModel correctamente si aún no quiere usarla.

Mi consejo, para lograr lo que desea, es subclasificar QObject y proporcionar sus datos adicionales, ya que se denominan propiedades para usarlos en QML. Consulte esta página de las pautas de Qt sobre cómo enlazar su QObject con QML .

  1. Respuesta TweetItem.original : tienes undefined porque, porque tu TweetItem.original es, de hecho, None .
  2. No estoy seguro de lo que está intentando lograr, pero quiero aclarar algunos malentendidos posibles. QAbstractItemModel es una clase modelo, es un poco extraño verlo

     def data(self, index, role): return self.tweets[index.row()].data(role) 

ahí.