2013-03-09 50 views
1

我在寫一個Twitter客戶端。我實施了TweetItemTweetModel。問題是在TweetItem中有一個叫original的角色。我希望它指向原來的推文。在Python中返回一個角色中的對象,並獲得QML中另一個對象的引用

更新:我的代碼中有一些錯字。現在我修好了它們。

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返回一個對象,並使用它?

回答

2

正如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一樣。

+0

是的,這是要走的路線 – dant3 2013-04-17 17:07:05

+0

這是行得通的!非常感謝!我要關閉這個問題:) – 2013-04-18 01:52:10

+0

你的解決方案完美。但是在某些情況下Qt會出現段錯誤:http://stackoverflow.com/questions/16112136/pyqt-segfault-when-trying-to-get-a-sub-sub-property-in-qml – 2013-04-19 19:29:08

0
  1. 直截了當的回答:你有undefined,因爲,因爲你的TweetItem.original其實None
  2. 我不確定你想要完成什麼,但我想清除一些可能的誤解。 QAbstractItemModel是一個模型類也一樣,這是有些奇怪地看到

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

那裏。

+1

廣告2:只是好奇,爲什麼你認爲這很奇怪?如果是因爲將數據委託給推文,這只是在Qt的一個例子中完成的,除了OP也通過這個角色之外:http://qt-project.org/doc/qt- 4.8/itemviews-simpletreemodel-treemodel-cpp.html – rainer 2013-03-11 09:33:48

+0

'TweetItem.original'不是None,我可以在Python中獲取對象,但是我在QML中未定義。也許這是垃圾回收的問題? – 2013-04-15 09:12:03

2

我的猜測是你沒有定義,不是訪問你的TweetItem對象,而是試圖讓id脫離它。

,因爲它看起來,你在TweetItem化QAbstractItemModel的實現僅僅是不正確。數據方法不接受任何索引,也不實現rowCount。如果您仍然不想使用它,請參考Qt文檔以瞭解如何實現QAbstractItemModel接口。

爲了達到您的目的,我的建議是將QObject轉換爲子類,並提供您的其他數據作爲其命名屬性以在QML中使用它們。看到這個page of Qt guidelines on how to bind your QObject with QML

+0

我發現我無法訪問TweetItem的任何屬性/插槽。即使它是'QObject'的簡單子類。我怎樣才能將它們動態地導出到QML? – 2013-04-17 09:22:30

+0

嘗試[qmlRegisterType函數](http://qt-project.org/doc/qt-4.8/qdeclarativeengine.html#qmlRegisterType) – dant3 2013-04-17 09:28:13

+0

我試過了。我的應用程序將在我qmlRegisterType(TweetItem,「tweetItem」,1,0,「tweetItem」)'之後被破壞。 QML引擎說'不能將對象分配給列表'。但我甚至沒有導入它?! – 2013-04-17 09:59:28

相關問題