Вернуть объект в роли в 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.

  1. Прямой ответ: вы получили undefined потому что, потому что ваш TweetItem.original на самом деле None,
  2. Я не уверен, чего вы пытаетесь достичь, но я хочу устранить некоторые возможные недоразумения. QAbstractItemModel это тоже модельный класс, странно видеть

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

там.

Другие вопросы по тегам