写作思路
1、简易QTreeView的使用(搞懂QTreeView Model 之间的关系)
2、QStyledItemDelegate + QAbstractListModel自定义Model(自定义Model的使用,以及自定义Model内部需要重构的方法的意义)
1、简易QTreeView的使用
import sys
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QMainWindow, QApplication, QTreeView
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.treeView = None
self.initUI()
def initUI(self):
self.treeView = QTreeView()
model = QStandardItemModel()
for row in range(4):
item = QStandardItem(str(row))
model.appendRow(item)
self.treeView.setModel(model)
self.treeView.show()
self.treeView.setWindowTitle("SimpleTree")
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
运行结果如下
首先了解一下各个Model的继承关系(如下图)以及使用规则
参考的内容,包括使用解析
用法比较简单,QStandardItemModel可以使用QStandardItem,通过不断添加子节点,从而构建出list、table、tree结构的数据。
使用QStandardItemModel表示数据集具有以下优点:
实现代码简单,该类使用QStandardItem存放数据项,用户不必定义任何数据结构来存放数据项;
QStandardItem使用自关联关系,能够表达列表、表格、树甚至更复杂的数据结构,能够涵盖各种各样的数据集;
QStandardItem本身存放着多个『角色,数据子项』,视图类、委托类或者其他用户定义的类能够方便地依据角色访问各个数据子项。
缺点:
当数据集中的数据项很多时,施加在数据集上的某些操作的执行效率会很低。
数据太大时,占用内存巨大,性能低下
QTreeView中关于 row column parent的定义:
在获取不同的对象时如下:
A节点:QModelIndex indexA = model->index(0, 0, QModelIndex());
B节点:QModelIndex indexC = model->index(2, 1, QModelIndex());
C节点:QModelIndex indexB = model->index(1, 0, indexA);
这个东西先记者,以后你会用到的
2、QStyledItemDelegate + QAbstractListModel自定义Model
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QApplication, QTreeView, QWidget, QPushButton, QVBoxLayout, QStyledItemDelegate
class Window(QWidget):
changeStyleTriggered = pyqtSignal()
def __init__(self):
super(Window, self).__init__()
self.createTree()
def createTree(self):
data = ['A', 'B', 'C', 'D', 'E', 'F']
model = MyTreeView(data)
self.treeView = QTreeView()
self.treeView.setItemDelegate(BoldDelegate())
self.treeView.setModel(model)
layout = QVBoxLayout()
layout.addWidget(self.treeView)
self.setStyleSheet("QTreeView::indicator:checked {image: url(door-closed-fill.svg)}"
"QTreeView::indicator:unchecked {image: url(door-open-fill.svg)}")
self.setLayout(layout)
class TestItem():
def __init__(self, name, checked):
self.checked = checked
self.name = name
class BoldDelegate(QStyledItemDelegate):
def paint(self, painter, option, index):
option.font.setWeight(QFont.Bold)
QStyledItemDelegate.paint(self, painter, option, index)
class MyTreeView(QAbstractListModel):
def __init__(self, args, parent=None):
super(MyTreeView, self).__init__(parent)
self.args = []
for item_name in args:
self.args.append(TestItem(item_name, False))
def rowCount(self, parent):
return len(self.args)
def headerData(self, section, orientation, role):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
return "Nodes"
def flags(self, index):
return Qt.ItemIsUserCheckable | Qt.ItemIsEditable | Qt.ItemIsSelectable | Qt.ItemIsEnabled
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
row = index.row()
return self.args[row].name
if role == Qt.CheckStateRole:
row = index.row()
if self.args[row].checked == False:
return Qt.Unchecked
else:
return Qt.Checked
def setData(self, index, value, role):
if role == Qt.CheckStateRole:
row = index.row()
self.args[row].checked = not self.args[row].checked
return True
def main():
myapp = QApplication(sys.argv)
window = Window()
window.show()
myapp.exec_()
if __name__ == '__main__':
main()
上述代码效果如下图
先大体的解释一下上述的过程:
①创建一个继承自QAbstractListModel的对象
②将数据data设置给上述Model对象
③通过各自View的SetModel方法,将Model设置给View
接下来一一解释上面各个函数的作用:
①rowCount(self, parent):返回行数(关于行的定义在上面截屏),假如此时改成 return 2,那么将只显示 A B两个子节点
②headerData(self, section, orientation, role): 修改标题的数据,orientation就是方向,role在上一篇博文已经介绍过了触发事件及QTableView的使用
③flags(self, index):就是对每一个数据项能否做什么处理的一个标记,以Qt.ItemIsUserCheckable为例,如果此处删去Qt.ItemIsUserCheckable,那么上图gif中,那个门就不能控制了~再比如Qt.ItemIsSelectable,如果删去,那么就不可选中,具体效果可以自己去尝试
④data(self, index, role=Qt.DisplayRole):对应view中的数据要如何显示(在这里就是QTreeView),如何处理,比如Qt.DisplayRole,就是设置数据该如何显示的;Qt.CheckStateRole就是那个门(其实就是一个勾选框,只是我在
self.setStyleSheet(“QTreeView::indicator:checked {image: url(door-closed-fill.svg)}”
“QTreeView::indicator:unchecked {image: url(door-open-fill.svg)}”)
这段代码里面修改了表现形式,删去就可以看到标准形式
⑤setData(self, index, value, role): 当我们修改数据之后,数据要怎么变化,比如这里就是说当我们修改了勾选框猴,数据内的选中标志取反
补充一下:
①在上述代码中创建了一个BoldDelegate类,继承自 QStyledItemDelegate ,通过创建这个类对象,并通过调用对应View的 setItemDelegate(BoldDelegate()) 就能设置数据的格式
②上面有一个类TestItem,这个类相当于是对传入的数据做一个处理,让其变成我们想要的结构类型,这里数据较为简单,因此就相当于struct
自己去探索吧~
QAbstractListModel是继承自QAbstractItemModel,因此在QAbstractListModel中找不到的虚方法说明可以到QAbstractItemModel中去找
后面还有一篇更复杂的QTreeView博文,后面补