PyQt5 QListView 使用自定义数据模型

3,444 阅读2分钟

在使用 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 的定义是通用的,一些 roleQListView 里并不会被使用。比如 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()

需要注意的是,在增删自定义数据列表的时候,需要在操作前后 beginend ,这样操作的结果才会同步到 UI 上。

修改数据数据时不需要 beginend ,但是需要调用 dataChanged() 以通知 UI 刷新数据,在通知时还需要指定变化的起始行,结束行和有变化的 role

不调用也可以,当修改的那一行从未选中状态变成选中状态时也会自动刷新数据。

也可以通过连续调用 QListViewclearFocus()setFocus() 来实现当前列表所有可见数据的刷新。

使用

使用上和 QStringListModel 一样,创建一个 Model 对象,然后赋值给 listView 即可。

list_model = MyListModel()
self.listView.setModel(list_model)