Python 在继承QabstrcTiteModel、PyQt时,将列表用作QModelIndex中的内部指针
我试图用Python中的QabstracteModel包装一个列表,以允许我使用PyQt附带的GUI将列表作为树来查看。确切地说,我使用的是PyQt5和Python3.3 我试图显式地生成指向列表项的指针,但在识别父项时遇到了问题。我不分配它们,也不确定在执行createIndex时PyQt是如何或是否分配它们的。然后,我决定重写代码,以明确标识使用索引(行值)访问的项,例如,给定嵌套列表[“a”,“a”,“1,2,3],“B”,“C”,“B”,“4,5,6],“d”]],然后我可以使用[4,1,1]指向5,然后使用相同的列表减去最后一项[4,1]检索父项 我的问题是这个。当我使用从行值生成的列表时,CREATEINDEX方法会使代码崩溃。我的最小断裂示例(MBE)如下所示。在这两行中取消注释“return self.createIndex(row,col,ptr)”以查看我描述的分解Python 在继承QabstrcTiteModel、PyQt时,将列表用作QModelIndex中的内部指针,python,list,qabstractitemmodel,pyqt5,Python,List,Qabstractitemmodel,Pyqt5,我试图用Python中的QabstracteModel包装一个列表,以允许我使用PyQt附带的GUI将列表作为树来查看。确切地说,我使用的是PyQt5和Python3.3 我试图显式地生成指向列表项的指针,但在识别父项时遇到了问题。我不分配它们,也不确定在执行createIndex时PyQt是如何或是否分配它们的。然后,我决定重写代码,以明确标识使用索引(行值)访问的项,例如,给定嵌套列表[“a”,“a”,“1,2,3],“B”,“C”,“B”,“4,5,6],“d”]],然后我可以使用[4,1
from PyQt5.QtGui import QFont, QColor
from PyQt5.QtCore import QAbstractItemModel, QModelIndex, Qt, QAbstractListModel, QAbstractTableModel, QSize, QVariant
from PyQt5.QtWidgets import QApplication, QTreeView, QTableView, QListView
class NodeTree(QAbstractItemModel) :
def __init__(self,parent,data) :
super(NodeTree,self).__init__(parent)
self.data = data
def rowCount(self, parent = QModelIndex()) :
# int rowCount (self, QModelIndex parent = QModelIndex())
if parent.isValid() :
data = self.data
for idx in parent.internalPointer() :
data = data[idx]
return len(data)
else :
return len(self.data)
def columnCount(self, parent = QModelIndex()) :
# int columnCount (self, QModelIndex parent = QModelIndex())
return 1
def data(self, index = QModelIndex(), role = None) :
# QVariant data (self, QModelIndex index, int role = Qt.DisplayRole)
if role == 0 :
if index.isValid() :
return str(index.internalPointer())
else :
return "No Data"
return None
def index(self,row,col, parent = QModelIndex()):
# QModelIndex index (self, int row, int column, QModelIndex parent = QModelIndex())
# QModelIndex createIndex (self, int arow, int acolumn, int aid)
# QModelIndex createIndex (self, int arow, int acolumn, object adata = 0)
if parent.isValid() :
ptr = [parent.internalPointer(),row]
# return self.createIndex(row,col,ptr)
return QModelIndex()
else :
ptr = [row]
# return self.createIndex(row,col,ptr)
return QModelIndex()
return QModelIndex()
def parent(self, child = QModelIndex()):
# QObject parent (self)
if child.isValid() :
print(child.internalPointer())
return QModelIndex()
if __name__ == "__main__" :
# http://blog.mathieu-leplatre.info/filesystem-watch-with-pyqt4.html
import sys
app = QApplication(sys.argv)
TreeView = QTreeView()
TreeModel = NodeTree(TreeView, [['A',['a',1]],['C','D'],['E','F']])
TreeView.setModel(TreeModel)
TreeView.show()
app.exec_()
我不理解的是QModelIndex是如何在CREATEINDEX中创建的,以及为什么它会因为INDEX方法中动态生成的列表而崩溃。对我来说,调用之间应该保留INTERNALPOINTER,然后传递一个列表就可以了
另一件让我困惑的事情是何时以及为什么调用父级和索引。据我所知,索引向下遍历树,父级向上遍历。因此,对索引的调用在(行、列)处标识父对象的子对象,而父对象是子对象并确定父对象。是否参照内部指针完成?如果是这样,为什么QmodelIndex要维护它自己的父方法呢。Qt似乎维护自己的内部树,该树根据索引和父项之间的调用建立项之间的层次结构。也就是说,始终有两棵树,一棵用于我的模型,另一棵用于显示 我想您的帮助是从这个输入列表中获得的
[['A',['a',1]],['C','D'],['E','F']]
以下输出
您的代码主要在以下几点上失败(我认为):
- 您没有拆分树模型和树项数据,这会产生一些混乱
- 与第一点相关,您可以根据数据计算某些属性,而不仅仅是基于Qt ModelIndex
我希望这能对您有所帮助。我尝试了同样的方法,还发现python随后崩溃。问题是C++和Python垃圾收集器之间的交互。创建QModelIndex时,传入python列表对象。PyScess在C++结构中存储一个指向此指针,但不告诉GC。这意味着python看不到任何引用列表的内容,GC将释放它。同时,C++ QMODEL索引会被传递到视图。视图调用将C++模式索引返回到Python代码中的数据(index)(或任何其他函数)。PySide然后创建一个新的QModelIndex对象。但是现在,内部指针指向不再存在的东西,各种各样的乐趣都可以保证
注意:如果您将列表存储在一个持久性结构(比函数的寿命更长的结构)中,那么您的方法是有效的。但这与使用路径列表作为内部指针的目的背道而驰。这就很好地解释了这种行为。我最终选择了萨尔瓦托雷回答中概述的方法。当它与一点元魔法混合在一起时,它会变得非常强大,例如,你可以将原始数据结构包装成一棵树。在比较多棵树时,使用列表作为索引仍然很有吸引力,但我从未经历过这个阶段。也许可以将键存储在键值存储中?然后可以简单地传递一个字符串并查找列表,或者这也是GC?
from PyQt5.QtCore import (
QAbstractItemModel,
QModelIndex,
Qt,
QVariant
)
from PyQt5.QtWidgets import QApplication, QTreeView
class TreeItem(object):
def __init__(self, content, parentItem):
self.content = content
self.parentItem = parentItem
self.childItems = []
def appendChild(self, item):
self.childItems.append(item)
def child(self, row):
return self.childItems[row]
def childCount(self):
return len(self.childItems)
def columnCount(self):
return 1
def data(self, column):
if self.content != None and column == 0:
return QVariant(self.content)
return QVariant()
def parent(self):
return self.parentItem
def row(self):
if self.parentItem:
return self.parentItem.childItems.index(self)
return 0
class NodeTree(QAbstractItemModel):
def __init__(self,parent,data) :
super(NodeTree,self).__init__(parent)
self.rootItem = TreeItem(None, None)
self.parents = {0 : self.rootItem}
self.setupModelData(self.rootItem, data)
def setupModelData(self, root, data):
for el in data:
if isinstance(el, list):
item = TreeItem("Node", root)
self.setupModelData(item, el)
else:
item = TreeItem(el, root)
root.appendChild(item)
def rowCount(self, parent = QModelIndex()):
if parent.column() > 0:
return 0
if not parent.isValid():
p_Item = self.rootItem
else:
p_Item = parent.internalPointer()
return p_Item.childCount()
def columnCount(self, parent = QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid():
return QVariant()
item = index.internalPointer()
if role == Qt.DisplayRole:
return item.data(index.column())
if role == Qt.UserRole:
if item:
return item.content
return QVariant()
def headerData(self, column, orientation, role):
if (orientation == Qt.Horizontal and
role == Qt.DisplayRole):
return QVariant("Content")
return QVariant()
def index(self, row, column, parent):
if not self.hasIndex(row, column, parent):
return QModelIndex()
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
childItem = parentItem.child(row)
if childItem:
return self.createIndex(row, column, childItem)
else:
return QModelIndex()
def parent(self, index):
if not index.isValid():
return QModelIndex()
childItem = index.internalPointer()
if not childItem:
return QModelIndex()
parentItem = childItem.parent()
if parentItem == self.rootItem:
return QModelIndex()
return self.createIndex(parentItem.row(), 0, parentItem)
if __name__ == "__main__" :
# http://blog.mathieu-leplatre.info/filesystem-watch-with-pyqt4.html
import sys
app = QApplication(sys.argv)
TreeView = QTreeView()
TreeModel = NodeTree(TreeView, [['A',['a',1]],['C','D'],['E','F']])
TreeView.setModel(TreeModel)
TreeView.show()
app.exec_()