当前位置: 首页 > news >正文

QAbstractListModel 详细解析

概述

QAbstractListModel 是 Qt 框架中为列表视图提供数据的抽象基类,它是 QAbstractItemModel 的简化版本,专门用于一维列表数据。

QObject
└── QAbstractItemModel└── QAbstractListModel

核心特性

1. 简化的一维数据模型

  • 专门为列表数据设计(ListView、Repeater等)

  • 不需要处理复杂的行列和父子关系

  • 相比 QAbstractItemModel 更易于实现

2. 自动索引管理

  • 自动为每个数据项创建 QModelIndex

  • 索引的 row 对应列表位置,column 始终为 0

  • parent 索引始终为无效索引

🎯 必须重写的纯虚函数

1. rowCount()

int rowCount(const QModelIndex &parent = QModelIndex()) const override;

作用: 返回模型中的数据行数
参数: parent - 对于列表模型,此参数应始终为无效索引
返回: 数据项的总数

示例:

int StudentModel::rowCount(const QModelIndex &parent) const
{// 列表模型中parent应该无效if (parent.isValid())return 0;return m_students.size();
}

2. data()

QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

作用: 返回指定索引和角色的数据
参数:

  • index: 数据项索引(row, column)

  • role: 数据角色(显示、装饰、工具提示等)

返回: 包含数据的 QVariant

示例:

QVariant StudentModel::data(const QModelIndex &index, int role) const
{// 检查索引有效性if (!index.isValid() || index.row() < 0 || index.row() >= m_students.size())return QVariant();const Student &student = m_students.at(index.row());switch (role) {case Qt::DisplayRole:case NameRole:return student.name;case AgeRole:return student.age;case ScoreRole:return student.score;// ... 其他角色default:return QVariant();}
}

3. roleNames()

QHash<int, QByteArray> roleNames() const override;

作用: 定义角色ID与角色名称的映射关系
返回: 角色ID到角色名称的哈希表

示例:

QHash<int, QByteArray> StudentModel::roleNames() const
{QHash<int, QByteArray> roles;roles[NameRole] = "name";roles[AgeRole] = "age";roles[ScoreRole] = "score";roles[ColorRole] = "color";return roles;
}

数据变更通知机制

1. 数据插入

void insertData(int position, int count)
{beginInsertRows(QModelIndex(), position, position + count - 1);// ... 实际插入数据操作endInsertRows();
}

2. 数据删除

void removeData(int position, int count)
{beginRemoveRows(QModelIndex(), position, position + count - 1);// ... 实际删除数据操作endRemoveRows();
}

3. 数据修改

void updateData(int position)
{QModelIndex topLeft = createIndex(position, 0);QModelIndex bottomRight = createIndex(position, 0);emit dataChanged(topLeft, bottomRight, {ScoreRole, ColorRole});
}

4. 模型重置

void resetModel()
{beginResetModel();// ... 完全重置数据endResetModel();
}

📊 内置数据角色

Qt 提供了一些标准角色:

角色描述
Qt::DisplayRole0主要显示数据
Qt::DecorationRole1图标等装饰数据
Qt::EditRole2可编辑的数据
Qt::ToolTipRole3工具提示文本
Qt::StatusTipRole4状态栏提示
Qt::WhatsThisRole5"这是什么"帮助
Qt::SizeHintRole13项的大小提示

🛠️ 完整实现示例

基础列表模型

class StringListModel : public QAbstractListModel
{Q_OBJECTpublic:explicit StringListModel(const QStringList &strings, QObject *parent = nullptr): QAbstractListModel(parent), m_strings(strings) {}int rowCount(const QModelIndex &parent = QModelIndex()) const override{if (parent.isValid())return 0;return m_strings.size();}QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override{if (!index.isValid() || index.row() >= m_strings.size())return QVariant();if (role == Qt::DisplayRole || role == Qt::EditRole)return m_strings.at(index.row());return QVariant();}QHash<int, QByteArray> roleNames() const override{QHash<int, QByteArray> roles;roles[Qt::DisplayRole] = "display";return roles;}private:QStringList m_strings;
};

高级自定义模型

class AdvancedListModel : public QAbstractListModel
{Q_OBJECTQ_PROPERTY(int count READ rowCount NOTIFY countChanged)public:enum CustomRoles {TitleRole = Qt::UserRole + 1,DescriptionRole,IconRole,ProgressRole,StatusRole};explicit AdvancedListModel(QObject *parent = nullptr) : QAbstractListModel(parent) {}// 必须实现的方法int rowCount(const QModelIndex &parent = QModelIndex()) const override{Q_UNUSED(parent)return m_items.size();}QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override{if (!index.isValid() || index.row() < 0 || index.row() >= m_items.size())return QVariant();const DataItem &item = m_items.at(index.row());switch (role) {case TitleRole:case Qt::DisplayRole:return item.title;case DescriptionRole:return item.description;case IconRole:return item.icon;case ProgressRole:return item.progress;case StatusRole:return item.status;case Qt::ToolTipRole:return QString("%1\n%2").arg(item.title).arg(item.description);default:return QVariant();}}QHash<int, QByteArray> roleNames() const override{QHash<int, QByteArray> roles;roles[TitleRole] = "title";roles[DescriptionRole] = "description";roles[IconRole] = "icon";roles[ProgressRole] = "progress";roles[StatusRole] = "status";return roles;}// 自定义方法Q_INVOKABLE void addItem(const QString &title, const QString &description){beginInsertRows(QModelIndex(), rowCount(), rowCount());m_items.append(DataItem{title, description, "default.png", 0, "active"});endInsertRows();emit countChanged();}Q_INVOKABLE void removeItem(int index){if (index < 0 || index >= m_items.size())return;beginRemoveRows(QModelIndex(), index, index);m_items.removeAt(index);endRemoveRows();emit countChanged();}Q_INVOKABLE void updateProgress(int index, int progress){if (index < 0 || index >= m_items.size())return;m_items[index].progress = progress;QModelIndex modelIndex = createIndex(index, 0);emit dataChanged(modelIndex, modelIndex, {ProgressRole});}signals:void countChanged();private:struct DataItem {QString title;QString description;QString icon;int progress;QString status;};QList<DataItem> m_items;
};

🔗 QML 中的使用

基本使用

ListView {model: advancedModeldelegate: Rectangle {width: parent.widthheight: 60Row {spacing: 10Image {source: model.iconwidth: 40; height: 40}Column {Text { text: model.title; font.bold: true }Text { text: model.description; color: "gray" }}ProgressBar {value: model.progresswidth: 100}}}
}

角色访问方式

// 方式1: 通过角色名直接访问
text: model.title// 方式2: 通过 modelData 访问(当只有 DisplayRole 时)
text: model.modelData// 方式3: 通过索引访问
text: model.display

⚡ 性能优化技巧

1. 批量操作

// 不好的做法:逐个添加
for (const auto &item : items) {beginInsertRows(...);// 添加一个endInsertRows();
}// 好的做法:批量添加
beginInsertRows(QModelIndex(), rowCount(), rowCount() + items.size() - 1);
m_items.append(items);
endInsertRows();

2. 精确的数据变更通知

// 只通知实际变化的角色
emit dataChanged(index, index, {SpecificRole});// 而不是通知所有角色
emit dataChanged(index, index);

3. 使用正确的父索引

// 列表模型始终使用无效的父索引
beginInsertRows(QModelIndex(), ...);
beginRemoveRows(QModelIndex(), ...);

🎨 高级特性

1. 可编辑模型

bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
{if (!index.isValid() || role != Qt::EditRole)return false;m_data[index.row()] = value.toString();emit dataChanged(index, index, {role});return true;
}Qt::ItemFlags flags(const QModelIndex &index) const override
{if (!index.isValid())return Qt::NoItemFlags;return Qt::ItemIsEditable | QAbstractListModel::flags(index);
}

2. 拖放支持

Qt::DropActions supportedDropActions() const override
{return Qt::MoveAction;
}QMimeData *mimeData(const QModelIndexList &indexes) const override
{// 实现 MIME 数据创建
}bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
{// 实现拖放数据处理
}

🔍 调试技巧

1. 角色名称调试

void printRoleNames()
{auto roles = roleNames();for (auto it = roles.begin(); it != roles.end(); ++it) {qDebug() << "Role:" << it.key() << "Name:" << it.value();}
}

2. 数据验证

bool isIndexValid(const QModelIndex &index) const
{return index.isValid() && index.row() >= 0 && index.row() < rowCount() && index.model() == this;
}

QAbstractListModel 提供了强大而灵活的方式来管理列表数据,通过与 Qt 的视图组件(特别是 QML ListView)紧密集成,可以创建高性能、响应式的用户界面。

http://www.dtcms.com/a/577538.html

相关文章:

  • 2025自动化运维厂商选型指南:数字化转型下,自动化运维平台为何成为“必选项”?
  • 如何把宏观战略转化为可执行的产品计划
  • 店铺设计素材针对网站做搜索引擎做优化
  • 温州网站排名优化公司哪家好网站推广服务合同模板
  • vscode-python学习-启动
  • STM32 串口线A-B
  • 使用 dnsmasq 搭建本地 DNS 服务器完整指南
  • 水墨画风格网站wordpress大气摄影主题
  • 详细介绍一下“集中同步+分布式入库”方案的具体实现步骤
  • 网站建设需要上传数据库吗双创网站建设
  • 轻量级Kafka集群管理工具
  • 嵌入式计算架构变革:ARM 浪潮下的替代革命与杰和科技产品布局
  • HarmonyOs鸿蒙开发,日期滑动选择器
  • 鸿蒙ArkUI布局与样式进阶(十六)——页面级变量、函数注入与 @BuilderParam 插槽机制全解析(附详细注释)
  • 网站加载页面怎么做seo网站设计外包
  • sqlserver2019中,一列为计算项目,一列为计算公式及计算项目代表的数字,如何找出一个计算项目是数字改变时,会有多个涉及的计算项目
  • 网站截图可以做证据吗微信小程序模板免费下载
  • 手机兼容测试服务提供商对比分析:腾讯优测Utest的优势与挑战
  • repo xml语法
  • 如何选择能够高效运行的云手机
  • IFC转换为3DXML的技术指南在线转换推荐
  • 站长之家工具网页界面设计的内容五大设计要素
  • MAUI劝退:内部消息机制(社区工具包)
  • 西安 网站 公司wordpress同步微信公众号
  • Xshell效率实战:SSH管理秘籍技术大纲
  • 和平精英java 游戏程序
  • 【Java】异常详解+实例演示+知识总结
  • 【大模型训练】sglang 权重绑定和roll HF Meg相互转化
  • 有那个网站可以做报名链接的网站开发项目简单描述
  • C++ 链表 模拟 递归 迭代 力扣 24. 两两交换链表中的节点 题解 每日一题