在使用 QListView 显示列表数据时,比较常用的是 QStringListModel ,但 QStringListModel 的功能比较单调,只能使用字符串,也修改不了字体颜色、背景色等多种属性。
要实现传入对象,修改颜色等更多的功能,需要自定义数据模型。
创建
创建一个基于 PyQt5.QtCore.QAbstractListModel 类的数据模型。
class MyListModel(QAbstractListModel):
def __init__(self):
super().__init__()
self._data_list = [] # 数据list,保存所有数据
继承后有 data() 和 rowCount() 两个方法必须要实现。
def data(self, index: QModelIndex, role: int = ...):
"""
继承父类,必须有。设置不同类型调用返回数据
:param index: 索引
:param role: 要获取的数据类型
:return:
"""
# 设置表格显示使用的数据
if index.isValid() or (0 <= index.row() < len(self._data_list)):
if role == Qt.DisplayRole:
return QVariant(self._data_list[index.row()]['name'])
elif role == Qt.BackgroundRole:
if self._data_list[index.row()].id != 0:
return QBrush(QColor(84, 255, 159))
else:
return QBrush(QColor(255, 255, 255))
else:
return QVariant()
def rowCount(self, parent: QModelIndex = ...) -> int:
"""
继承父类,必须有。返回数据总行数
:param parent:
:return:
"""
return len(self._data_list)
比较常用的 role 有
- Qt.DisplayRole:显示在界面上的内容
- Qt.ForegroundRole:前景色(通常是文字颜色)
- Qt.BackgroundRole:背景色(整行)
其他类型可以参考 ItemDataRole
需要注意的是 role 的定义是通用的,一些 role 在 QListView 里并不会被使用。比如 StatusTipRole 。
增删改清
def add_item(self, item_data):
"""
自定义。添加单个数据
:param item_data: 数据
:return:
"""
if item_data:
self.beginInsertRows(QModelIndex(), len(self._data_list), len(self._data_list) + 1)
self._data_list.append(item_data)
self.endInsertRows()
def delete_item(self, row):
"""
自定义。删除数据
:param row: 索引
:return:
"""
self.beginRemoveRows(QModelIndex(), row, row - 1)
del self._data_list[row]
self.endRemoveRows()
def update_item(self, index, new_item):
"""
自定义。更新数据
:param index: 索引
:param new_item: 新数据
:return:
"""
self._data_list[index.row()] = new_item
self.dataChanged(index, index, Qt.BackgroundRole)
def clear(self):
"""
清空数据
:return:
"""
self.beginResetModel()
self._data_list.clear()
self.endResetModel()
需要注意的是,在增删自定义数据列表的时候,需要在操作前后 begin 和 end ,这样操作的结果才会同步到 UI 上。
修改数据数据时不需要 begin 和 end ,但是需要调用 dataChanged() 以通知 UI 刷新数据,在通知时还需要指定变化的起始行,结束行和有变化的 role 。
不调用也可以,当修改的那一行从未选中状态变成选中状态时也会自动刷新数据。
也可以通过连续调用
QListView的clearFocus()和setFocus()来实现当前列表所有可见数据的刷新。
使用
使用上和 QStringListModel 一样,创建一个 Model 对象,然后赋值给 listView 即可。
list_model = MyListModel()
self.listView.setModel(list_model)