View/Model/Controller : 如何设计分层数据变量
View/Model/Controller : How to design hierarchical data variable
在PyQt4中Model-Viewtutorial作者
设计 Node()
Class 与 QAbstractItemModel
一起使用链接到 QTreeView
:
class Node(object):
def __init__(self, name, parent=None):
self._name = name
self._children=[]
self._parent=parent
if parent is not None:
parent.addChild(self)
def typeInfo(self):
return "NODE"
def addChild(self, child):
self._children.append(child)
def name(self):
return self._name
def setName(self, name):
self._name = name
def child(self, row):
return self._children[row]
def childCount(self):
return len(self._children)
def parent(self):
return self._parent
def row(self):
if self._parent is not None:
return self._parent._children.index(self)
然后他继续声明数据变量本身。
首先,他声明一个 rootNode
变量用作所有顶级 item-variables:
的 parent
rootNode = Node("Root")
然后他声明了两个顶级item-variablesA和B:childNodeA0
和childNodeB0
。
并且对于这两个 top-level item-variables 中的每一个都声明了两个 child item-variables
(我重命名了变量以使事情看起来更通用):
childNodeA0 = Node("childNodeA0", rootNode)
childNodeA1 = Node("childNodeA1", childNodeA0)
childNodeA2 = Node("childNodeA2", childNodeA1)
childNodeB0 = Node("childNodeB0", rootNode)
childNodeB1 = Node("childNodeB1", childNodeB0)
childNodeB3 = Node("childNodeB3", childNodeB1)
这是存储在 rootNode 变量中的数据的示意图:
|------Root
|------childNodeA0
|------childNodeA1
|------childNodeA2
|------childNodeB0
|------childNodeB1
|------childNodeB3
现在我声明第三个项目变量 childNodeC0
:
childNodeC0 = Node("childNodeC0", rootNode)
我将 rootNode
作为其 parent。这是原理图:
|------Root
|------childNodeA0
|------childNodeA1
|------childNodeA2
|------childNodeB0
|------childNodeB1
|------childNodeB3
|------childNodeC0
现在使用 .addChild()
方法,我将 childNodeC0
变量附加为 childNodeB0
的 child。
所以 childNodeC0
是两个变量的 child:它是 rootNode
和 childNodeB0
:
的 child
childNodeB0.addChild(childNodeC0)
原理图如下:
|------Root
|------childNodeA0
|------childNodeA1
|------childNodeA2
|------childNodeB0
|------childNodeB1
|------childNodeB3
|------childNodeC0
|------childNodeC0
一切如预期。但是,当此数据变量分配给 "real" 模型时,childNodeC0
item-variable 仅显示为 Root
的 child 而不是 child ] 的 childNodeB0
。除此之外,childNodeB0
item-variable 在 TreeView 中显示了两次:作为 Root 的 child(因为它应该是)。而且它本身也显示为child!:
问题:
如何让 TreeView 正确显示存储在根变量中的数据?
from PyQt4 import QtCore, QtGui
import sys
class Node(object):
def __init__(self, name, parent=None):
self._name = name
self._children=[]
self._parent=parent
if parent is not None:
parent.addChild(self)
def typeInfo(self):
return "NODE"
def addChild(self, child):
self._children.append(child)
def name(self):
return self._name
def setName(self, name):
self._name = name
def child(self, row):
return self._children[row]
def childCount(self):
return len(self._children)
def parent(self):
return self._parent
def row(self):
if self._parent is not None:
return self._parent._children.index(self)
def log(self, tabLevel=-1):
output = ""
tabLevel += 1
for i in range(tabLevel):
output += "\t"
output += "|------" + self._name + "\n"
for child in self._children:
output += child.log(tabLevel)
tabLevel -= 1
output += "\n"
return output
def __repr__(self):
return self.log()
class SceneGraphModel(QtCore.QAbstractItemModel):
def __init__(self, root, parent=None):
super(SceneGraphModel, self).__init__(parent)
self._rootNode = root
def rowCount(self, parent):
if not parent.isValid():
parentNode = self._rootNode
else:
parentNode = parent.internalPointer()
# print 'VALID: ', type(parent), parent.row(), parent.column()
return parentNode.childCount()
def columnCount(self, parent):
return 1
def data(self, index, role):
if not index.isValid():
return None
node = index.internalPointer()
if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
if index.column() == 0:
return node.name()
def setData(self, index, value, role=QtCore.Qt.EditRole):
if index.isValid():
if role == QtCore.Qt.EditRole:
node = index.internalPointer()
node.setName(value)
return True
return False
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if section == 0:
return "Column #0"
def flags(self, index):
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable
def parent(self, index):
node = self.getNode(index)
parentNode = node.parent()
if parentNode == self._rootNode:
return QtCore.QModelIndex()
return self.createIndex(parentNode.row(), 0, parentNode)
def index(self, row, column, parent):
parentNode = self.getNode(parent)
childItem = parentNode.child(row)
if childItem:
return self.createIndex(row, column, childItem)
else:
return QtCore.QModelIndex()
def getNode(self, index):
if index.isValid():
node = index.internalPointer()
if node:
return node
return self._rootNode
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
rootNode = Node("Root")
childNodeA0 = Node("childNodeA0", rootNode)
childNodeA1 = Node("childNodeA1", childNodeA0)
childNodeA2 = Node("childNodeA2", childNodeA1)
childNodeB0 = Node("childNodeB0", rootNode)
childNodeB1 = Node("childNodeB1", childNodeB0)
childNodeB3 = Node("childNodeB3", childNodeB1)
childNodeC0 = Node("childNodeC0", rootNode)
childNodeB0.addChild(childNodeC0)
treeView=QtGui.QTreeView()
model = SceneGraphModel(rootNode)
treeView.setModel(model)
treeView.show()
print rootNode
sys.exit(app.exec_())
我认为使用此数据模型,您不能让一个节点具有 2 个不同的 parent。
addChild
令人困惑,因为您似乎可以做到。
如果您查看场景图模型,它会询问 Node
因为它是 parent(在 parent(self, index)
中):
parentNode = node.parent()
和 Node.parent()
只有 returns parent 在项目的构造中定义:
return self._parent
如果您想在 2 个不同的位置拥有相同的 child,您可能需要复制它或改进数据模型。
在PyQt4中Model-Viewtutorial作者
设计 Node()
Class 与 QAbstractItemModel
一起使用链接到 QTreeView
:
class Node(object):
def __init__(self, name, parent=None):
self._name = name
self._children=[]
self._parent=parent
if parent is not None:
parent.addChild(self)
def typeInfo(self):
return "NODE"
def addChild(self, child):
self._children.append(child)
def name(self):
return self._name
def setName(self, name):
self._name = name
def child(self, row):
return self._children[row]
def childCount(self):
return len(self._children)
def parent(self):
return self._parent
def row(self):
if self._parent is not None:
return self._parent._children.index(self)
然后他继续声明数据变量本身。
首先,他声明一个 rootNode
变量用作所有顶级 item-variables:
rootNode = Node("Root")
然后他声明了两个顶级item-variablesA和B:childNodeA0
和childNodeB0
。
并且对于这两个 top-level item-variables 中的每一个都声明了两个 child item-variables
(我重命名了变量以使事情看起来更通用):
childNodeA0 = Node("childNodeA0", rootNode)
childNodeA1 = Node("childNodeA1", childNodeA0)
childNodeA2 = Node("childNodeA2", childNodeA1)
childNodeB0 = Node("childNodeB0", rootNode)
childNodeB1 = Node("childNodeB1", childNodeB0)
childNodeB3 = Node("childNodeB3", childNodeB1)
这是存储在 rootNode 变量中的数据的示意图:
|------Root
|------childNodeA0
|------childNodeA1
|------childNodeA2
|------childNodeB0
|------childNodeB1
|------childNodeB3
现在我声明第三个项目变量 childNodeC0
:
childNodeC0 = Node("childNodeC0", rootNode)
我将 rootNode
作为其 parent。这是原理图:
|------Root
|------childNodeA0
|------childNodeA1
|------childNodeA2
|------childNodeB0
|------childNodeB1
|------childNodeB3
|------childNodeC0
现在使用 .addChild()
方法,我将 childNodeC0
变量附加为 childNodeB0
的 child。
所以 childNodeC0
是两个变量的 child:它是 rootNode
和 childNodeB0
:
childNodeB0.addChild(childNodeC0)
原理图如下:
|------Root
|------childNodeA0
|------childNodeA1
|------childNodeA2
|------childNodeB0
|------childNodeB1
|------childNodeB3
|------childNodeC0
|------childNodeC0
一切如预期。但是,当此数据变量分配给 "real" 模型时,childNodeC0
item-variable 仅显示为 Root
的 child 而不是 child ] 的 childNodeB0
。除此之外,childNodeB0
item-variable 在 TreeView 中显示了两次:作为 Root 的 child(因为它应该是)。而且它本身也显示为child!:
问题:
如何让 TreeView 正确显示存储在根变量中的数据?
from PyQt4 import QtCore, QtGui
import sys
class Node(object):
def __init__(self, name, parent=None):
self._name = name
self._children=[]
self._parent=parent
if parent is not None:
parent.addChild(self)
def typeInfo(self):
return "NODE"
def addChild(self, child):
self._children.append(child)
def name(self):
return self._name
def setName(self, name):
self._name = name
def child(self, row):
return self._children[row]
def childCount(self):
return len(self._children)
def parent(self):
return self._parent
def row(self):
if self._parent is not None:
return self._parent._children.index(self)
def log(self, tabLevel=-1):
output = ""
tabLevel += 1
for i in range(tabLevel):
output += "\t"
output += "|------" + self._name + "\n"
for child in self._children:
output += child.log(tabLevel)
tabLevel -= 1
output += "\n"
return output
def __repr__(self):
return self.log()
class SceneGraphModel(QtCore.QAbstractItemModel):
def __init__(self, root, parent=None):
super(SceneGraphModel, self).__init__(parent)
self._rootNode = root
def rowCount(self, parent):
if not parent.isValid():
parentNode = self._rootNode
else:
parentNode = parent.internalPointer()
# print 'VALID: ', type(parent), parent.row(), parent.column()
return parentNode.childCount()
def columnCount(self, parent):
return 1
def data(self, index, role):
if not index.isValid():
return None
node = index.internalPointer()
if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
if index.column() == 0:
return node.name()
def setData(self, index, value, role=QtCore.Qt.EditRole):
if index.isValid():
if role == QtCore.Qt.EditRole:
node = index.internalPointer()
node.setName(value)
return True
return False
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if section == 0:
return "Column #0"
def flags(self, index):
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable
def parent(self, index):
node = self.getNode(index)
parentNode = node.parent()
if parentNode == self._rootNode:
return QtCore.QModelIndex()
return self.createIndex(parentNode.row(), 0, parentNode)
def index(self, row, column, parent):
parentNode = self.getNode(parent)
childItem = parentNode.child(row)
if childItem:
return self.createIndex(row, column, childItem)
else:
return QtCore.QModelIndex()
def getNode(self, index):
if index.isValid():
node = index.internalPointer()
if node:
return node
return self._rootNode
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
rootNode = Node("Root")
childNodeA0 = Node("childNodeA0", rootNode)
childNodeA1 = Node("childNodeA1", childNodeA0)
childNodeA2 = Node("childNodeA2", childNodeA1)
childNodeB0 = Node("childNodeB0", rootNode)
childNodeB1 = Node("childNodeB1", childNodeB0)
childNodeB3 = Node("childNodeB3", childNodeB1)
childNodeC0 = Node("childNodeC0", rootNode)
childNodeB0.addChild(childNodeC0)
treeView=QtGui.QTreeView()
model = SceneGraphModel(rootNode)
treeView.setModel(model)
treeView.show()
print rootNode
sys.exit(app.exec_())
我认为使用此数据模型,您不能让一个节点具有 2 个不同的 parent。
addChild
令人困惑,因为您似乎可以做到。
如果您查看场景图模型,它会询问 Node
因为它是 parent(在 parent(self, index)
中):
parentNode = node.parent()
和 Node.parent()
只有 returns parent 在项目的构造中定义:
return self._parent
如果您想在 2 个不同的位置拥有相同的 child,您可能需要复制它或改进数据模型。