PyQt5中的模型与视图框架-自定义模型的一个简单示例
针对PyQt5中的模型与视图框架,前文已非常详尽地讨论了抽象模型基类QAbstractItemModel与自定义模型的原理。在此基础之上,通过一个简单的示例程序,来巩固一下理解。
自定义表格模型示例代码如下:
from PyQt5.QtWidgets import QApplication, QWidget, QTableView, QHBoxLayout
from PyQt5.QtCore import QAbstractItemModel, QModelIndex, Qt
from PyQt5.QtGui import QIcon
import typing
import sys
class MyItem():
def __init__(self):
self.__data = 'N/A' # 存储模型管理的数据
self.__role = -1 # 存储数据的角色
@property
def data(self):
return self.__data
@data.setter
def data(self, value):
self.__data = value
@data.deleter
def data(self):
raise TypeError('cannot delete data')
@property
def role(self):
return self.__role
@role.setter
def role(self, value):
self.__role = value
@role.deleter
def role(self):
raise TypeError('cannot delete role')
class MyTableModel(QAbstractItemModel):
def __init__(self, row, column, parent=None) -> None:
super().__init__(parent)
self.__row = row # 表格模型的行数
self.__col = column # 表格模型的列数
self.__item_list = []
# 表格模型初始化
for k in range(0, row * column):
self.__item_list.append(MyItem())
def rowCount(self, parent=QModelIndex()) -> int:
'''
重写rowCount函数,返回表格模型的行数
'''
return self.__row
def columnCount(self, parent=QModelIndex()) -> int:
'''
重写columnCount函数,返回表格模型的列数
'''
return self.__col
def index(self, row: int, column: int, parent: QModelIndex = QModelIndex()) -> QModelIndex:
'''
重写index函数,为每个单元格创建一个唯一的索引
'''
# 这里只需简单创建一个索引即可
return super().createIndex(row, column, self.__item_list[row*column + column].data)
def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) -> typing.Any:
'''
重写data函数,返回视图上显示的数据,该函数会被视图多次调用
'''
# 获取单元格数据在self.__item_list中的下标位置
i = index.row() * self.__col + index.column()
# 对以下不同的角色所返回的数据,会被视图使用,且数据能正确地显示在单元格中
# 设置单元格中数据的对其方式
if role == Qt.ItemDataRole.TextAlignmentRole:
return Qt.AlignmentFlag.AlignLeft and Qt.AlignmentFlag.AlignCenter
# 设置角色DecorationRole(图片)的数据,
if role == Qt.ItemDataRole.DecorationRole:
# 如果用户设置了DecorationRole角色的数据,则需要返回该单元格设置的数据
if self.__item_list[i].role == Qt.ItemDataRole.DecorationRole:
return self.__item_list[i].data
# 如果用户为角色EditRole或者DisplayRole设置了数据,则需要返回用户为单元格设置的数据
if role == Qt.ItemDataRole.EditRole or role == Qt.ItemDataRole.DisplayRole:
return self.__item_list[i].data
# 其余角色使用无效数据
return None
def parent(self, index:QModelIndex) -> QModelIndex:
'''
重写parent方法,返回表格模型的父索引,因为所有单元格都是顶级节点,所以使用无效节点作为父节点
'''
return QModelIndex()
def setData(self, index: QModelIndex, value: typing.Any, role: int = Qt.ItemDataRole.EditRole) -> bool:
'''
重写setData方法,以使用户能够向模型中添加数据
'''
# 使用value和role分别替换原有的值
i = index.row() * self.__col + index.column()
self.__item_list[i].data = value
self.__item_list[i].role = role
# 数据改变后,需要发送信号
self.dataChanged.emit(index, index)
# 返回true,表示数据设置成功
return True
if __name__ == '__main__':
app = QApplication(sys.argv)
my_widget = QWidget()
# 创建一个3*3的表格模型
my_model = MyTableModel(3, 3)
# 创建一个表格视图来显示以上模型管理的数据
my_view = QTableView()
# 向模型中添加数据
my_model.setData(my_model.index(0, 0, QModelIndex()), 11, Qt.ItemDataRole.DisplayRole)
my_model.setData(my_model.index(1, 0, QModelIndex()), 21)
my_model.setData(my_model.index(1, 1, QModelIndex()), 22)
my_model.setData(my_model.index(2, 2, QModelIndex()), QIcon('C:\\Users\\hubing\\Pictures\\QQ图片20200112144947.jpg'), Qt.ItemDataRole.DecorationRole)
my_view.setModel(my_model)
my_layout = QHBoxLayout()
my_layout.addWidget(my_view)
my_widget.setLayout(my_layout)
my_widget.show()
sys.exit(app.exec_())
运行效果如下:
小手一抖,点个赞再走哦~~~