Вернуть объект в роли в Python и получить ссылку на другой объект в QML
Я пишу в Твиттере. Я реализовал TweetItem
а также TweetModel
, Проблема в том, что есть роль в TweetItem
называется original
, Я хочу, чтобы он указывал на оригинальный твит.
Обновление: в моем коде были опечатки. Теперь я их починил.
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 == <__main__.TweetItem object at 0x7fb703d95d40>
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_()
Но я не могу использовать его в QML. Я получаю 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 } }
}
}
Итак, возможно ли вернуть объект в role
и использовать это?
3 ответа
Как было предложено dant3 использовать QObject со свойствами.
Вот пример, как это сделать:
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_()
Файл QML остается прежним.
Я не сделал original
свойство, так как вы получаете его как данные модели, но вы можете сделать это так же, как id
,
Я предполагаю, что вы получили неопределенность не при доступе к объекту TweetItem, а при попытке получить из него идентификатор.
Похоже, что ваша реализация QAbstractItemModel в TweetItem просто неверна. Метод данных не принимает ни индекс, ни реализует rowCount. Обратитесь к документации Qt о том, как правильно реализовать интерфейс QAbstractItemModel, если вы все еще не хотите его использовать.
Мой совет, чтобы достичь того, чего вы хотите, это вместо этого создать подкласс QObject и предоставить ваши дополнительные данные в виде именованных свойств, чтобы использовать их в QML. Смотрите эту страницу руководства Qt о том, как связать ваш QObject с QML.
- Прямой ответ: вы получили
undefined
потому что, потому что вашTweetItem.original
на самом делеNone
, Я не уверен, чего вы пытаетесь достичь, но я хочу устранить некоторые возможные недоразумения.
QAbstractItemModel
это тоже модельный класс, странно видетьdef data(self, index, role): return self.tweets[index.row()].data(role)
там.