【PyQt5】QTreeView使用自定义Model

Python代码

TreeModel.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import PyQt5.Qt
import PyQt5.QtGui
from PyQt5.QtCore import QAbstractItemModel, QVariant, QModelIndex, Qt

class TreeItem:

def __init__(self, data, parent = None):
self.parentItem = parent # 父节点
self.childItems = [] # 子节点
self.itemData = data # 子节点对应数据
self._row = -1 # 此item位于父节点第几个

def appendChild(self, child):
child.setRow(len(self.childItems))
self.childItems.append(child)

def child(self, row):
return self.childItems[row]

def childCount(self):
return len(self.childItems)

def columnCount(self):
return len(self.itemData)

def data(self, column):
return self.itemData[column]

# 保存该节点是其父节点的第几个子节点,查询优化所用
def setRow(self, row: int):
self._row = row

# 返回本节点位于父节点下第几个子节点
def row(self):
return self._row

def parent(self):
return self.parentItem


class TreeModel(QAbstractItemModel):

def __init__(self, parent = None):
super(TreeModel, self).__init__()
self.rootItem = None # 最顶层根节点
self.updataData()

# 在parent节点下,第row行,第column列位置上创建索引
def data(self, index: QModelIndex, role: int = ...):
if not index.isValid():
return QVariant()
# 添加图标
if role == Qt.DecorationRole and index.column() == 0:
return PyQt5.QtGui.QIcon("images/snapshot.png")
# 显示节点数据值
if role == Qt.DisplayRole:
item = index.internalPointer()
return item.data(index.column())
return QVariant()

def flags(self, index: QModelIndex):
if not index.isValid():
return 0
return Qt.ItemIsEnabled | Qt.ItemIsSelectable

# 获取表头数据
def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> QVariant:
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.rootItem.data(section)
return QVariant()

# 在parent节点下,第row行,第column列位置上创建索引
def index(self, row: int, column: int, parent: QModelIndex = ...) -> QModelIndex:
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()

# 创建index的父索引
def parent(self, index: QModelIndex) -> QModelIndex:
if not index.isValid():
return QModelIndex()
childItem = index.internalPointer()
parentItem = childItem.parent()
# 顶层节点,直接返回空索引
if parentItem == self.rootItem:
return QModelIndex()
# 为父节点建立索引
return self.createIndex(parentItem.row(), 0, parentItem)

# 获取索引parent下有多少行
def rowCount(self, parent: QModelIndex = ...) -> int:
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
return parentItem.childCount() # 返回父节点下子节点数目

# 返回索引parent下有多少列
def columnCount(self, parent: QModelIndex = ...) -> int:
return self.rootItem.columnCount()

# 构建模型数据
def setupModelData(self, parent):
for i in range(10):
datas = [f"设备-{i + 1}", f"类型-{i + 1}"]
# 主节点下挂两个子节点
primary = TreeItem(datas, parent)
parent.appendChild(primary)

for j in range(2):
ds = [f"子设备-{j + 1}", f"子类型-{j + 1}"]
primary.appendChild(TreeItem(ds, primary))

# 更新模型数据
def updataData(self):
# 废弃旧模型数据
if self.rootItem:
del self.rootItem
self.rootItem = None

rootData = ['Tag', 'Type']
self.rootItem = TreeItem(rootData)
self.setupModelData(self.rootItem)

测试

关键测试代码如下:

1
2
3
self.model = TreeModel()
self.treeView = QTreeView(self)
self.treeView.setModel(self.model)

结果

image-20221116221218293

参考

[1] https://blog.csdn.net/specialsun/article/details/84437740

[2] https://blog.csdn.net/chenyijun/article/details/125564474


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!