Qt QStringListModel与QListView:高效列表数据展示的完整指南
在 Qt C 开发中数据与视图的分离是 GUI 编程的核心思想之一。当我们需要在界面上展示一个简单的字符串列表时QStringListModel 与 QListView 的组合提供了轻量且高效的解决方案。本文将深入探讨这对黄金搭档的完整用法从基础概念到实战应用涵盖数据操作、视图定制、信号交互等关键环节帮助开发者快速掌握列表数据展示的核心技能。1. QStringListModel 与 QListView 核心概念解析1.1 什么是 QStringListModelQStringListModel 是 Qt 框架中专门为字符串列表数据设计的模型类它继承自 QAbstractListModel。作为 Model-View 架构中的模型部分它负责管理数据的存储、访问和修改而不涉及任何界面显示逻辑。核心特性专为 QStringList 数据类型优化内存占用小操作效率高自动支持数据的增删改查操作提供标准接口与各种视图组件无缝对接内置数据变更通知机制视图会自动同步更新1.2 什么是 QListViewQListView 是用于显示列表数据的视图组件它继承自 QAbstractItemView。作为 Model-View 架构中的视图部分它负责数据的可视化呈现和用户交互。核心功能支持单列列表数据的多种显示模式列表、图标等提供选择模式控制单选、多选、扩展选择等支持拖拽操作和项编辑功能可自定义项渲染器和编辑器1.3 Model-View 架构优势使用 QStringListModel 和 QListView 的组合而不是直接操作 QListWidget具有以下显著优势数据与显示分离模型只关心数据存储视图只负责显示职责清晰代码复用性同一个模型可以被多个不同的视图组件共享使用性能优化对于大数据量场景模型可以按需提供数据减少内存占用标准化接口符合 Qt 的设计哲学便于扩展和维护2. 环境准备与项目配置2.1 开发环境要求在进行 QStringListModel 和 QListView 开发前需要确保环境配置正确基础环境Qt 5.12 或更高版本本文示例基于 Qt 6.2C11 或更高标准的编译器支持 Qt 的 IDEQt Creator、VS Code 等项目配置要点在 .pro 文件中确保包含必要的模块QT core gui widgets CONFIG c172.2 创建基础项目结构建议采用标准的主窗口应用程序结构项目目录/ ├── main.cpp ├── MainWindow.h ├── MainWindow.cpp ├── MainWindow.ui └── 项目文件.pro3. QStringListModel 核心用法详解3.1 创建与初始化模型QStringListModel 的创建非常简单支持多种初始化方式// 方式1空模型后设置数据 QStringListModel *model new QStringListModel(this); QStringList dataList; dataList 苹果 香蕉 橙子 葡萄; model-setStringList(dataList); // 方式2构造时直接传入数据 QStringList initialData {C, Java, Python, JavaScript}; QStringListModel *model new QStringListModel(initialData, this); // 方式3分步添加数据 QStringListModel *model new QStringListModel(this); model-insertRow(0); model-setData(model-index(0), 第一项);3.2 数据操作接口详解数据访问方法// 获取整个字符串列表 QStringList allData model-stringList(); // 获取特定位置的数据 QModelIndex index model-index(2); // 第三项 QString itemText model-data(index, Qt::DisplayRole).toString(); // 获取行数 int rowCount model-rowCount();数据修改操作// 修改现有项 QModelIndex targetIndex model-index(1); model-setData(targetIndex, 修改后的文本); // 添加新项 int newRow model-rowCount(); model-insertRow(newRow); model-setData(model-index(newRow), 新项目); // 删除项 model-removeRow(2); // 删除第三项3.3 信号与槽机制QStringListModel 提供丰富的信号用于监控数据变化// 连接数据变化信号 connect(model, QStringListModel::dataChanged, [](const QModelIndex topLeft, const QModelIndex bottomRight) { qDebug() 数据发生变化范围: topLeft.row() 到 bottomRight.row(); }); // 行变化信号 connect(model, QStringListModel::rowsInserted, [](const QModelIndex parent, int first, int last) { qDebug() 插入行: first 到 last; }); connect(model, QStringListModel::rowsAboutToBeRemoved, [](const QModelIndex parent, int first, int last) { qDebug() 即将删除行: first 到 last; });4. QListView 视图配置与定制4.1 基础视图配置QListView 提供丰富的显示选项满足不同场景需求// 创建并配置列表视图 QListView *listView new QListView(this); // 设置显示模式 listView-setViewMode(QListView::ListMode); // 列表模式 // listView-setViewMode(QListView::IconMode); // 图标模式 // 设置选择模式 listView-setSelectionMode(QAbstractItemView::SingleSelection); // 单选 // listView-setSelectionMode(QAbstractItemView::MultiSelection); // 多选 // listView-setSelectionMode(QAbstractItemView::ExtendedSelection); // 扩展选择 // 其他常用配置 listView-setDragEnabled(true); // 启用拖拽 listView-setAcceptDrops(true); // 接受拖放 listView-setEditTriggers(QAbstractItemView::DoubleClicked); // 双击编辑4.2 视觉样式定制通过样式表可以深度定制列表外观// 基础样式设置 listView-setStyleSheet( QListView { background-color: #f0f0f0; alternate-background-color: #e0e0e0; border: 1px solid #ccc; border-radius: 4px; } QListView::item { padding: 8px; border-bottom: 1px solid #ddd; } QListView::item:selected { background-color: #0078d4; color: white; } QListView::item:hover { background-color: #e6f3ff; } );4.3 项渲染器定制对于复杂显示需求可以自定义项委托class CustomItemDelegate : public QStyledItemDelegate { public: explicit CustomItemDelegate(QObject *parent nullptr) : QStyledItemDelegate(parent) {} void paint(QPainter *painter, const QStyleOptionViewItem option, const QModelIndex index) const override { // 自定义绘制逻辑 if (option.state QStyle::State_Selected) { painter-fillRect(option.rect, QColor(#0078d4)); } QString text index.data(Qt::DisplayRole).toString(); painter-drawText(option.rect.adjusted(10, 0, -10, 0), Qt::AlignLeft | Qt::AlignVCenter, text); } QSize sizeHint(const QStyleOptionViewItem option, const QModelIndex index) const override { return QSize(200, 40); // 固定项大小 } }; // 使用自定义委托 listView-setItemDelegate(new CustomItemDelegate(this));5. 完整实战案例通讯录管理系统5.1 项目需求分析我们实现一个简单的通讯录管理系统具备以下功能显示联系人列表添加新联系人删除选中联系人编辑联系人信息搜索过滤功能5.2 界面设计与布局创建主窗口界面包含列表视图和操作按钮// MainWindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include QMainWindow #include QStringListModel #include QListView #include QLineEdit #include QPushButton #include QVBoxLayout #include QHBoxLayout class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent nullptr); ~MainWindow(); private slots: void addContact(); void deleteContact(); void searchContact(const QString text); void onItemDoubleClicked(const QModelIndex index); private: void setupUI(); void setupConnections(); QListView *listView; QStringListModel *model; QLineEdit *searchEdit; QLineEdit *addEdit; QPushButton *addButton; QPushButton *deleteButton; QStringList originalData; // 保存原始数据用于搜索过滤 }; #endif // MAINWINDOW_H5.3 核心功能实现界面初始化与连接设置// MainWindow.cpp #include MainWindow.h #include QMessageBox MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { // 初始化数据 originalData {张三 - 13800138000, 李四 - 13900139000, 王五 - 13700137000}; setupUI(); setupConnections(); // 设置初始数据 model-setStringList(originalData); } void MainWindow::setupUI() { QWidget *centralWidget new QWidget(this); setCentralWidget(centralWidget); QVBoxLayout *mainLayout new QVBoxLayout(centralWidget); // 搜索区域 QHBoxLayout *searchLayout new QHBoxLayout(); searchEdit new QLineEdit(this); searchEdit-setPlaceholderText(搜索联系人...); searchLayout-addWidget(searchEdit); // 列表视图 listView new QListView(this); model new QStringListModel(this); listView-setModel(model); listView-setEditTriggers(QAbstractItemView::DoubleClicked); // 操作区域 QHBoxLayout *actionLayout new QHBoxLayout(); addEdit new QLineEdit(this); addEdit-setPlaceholderText(输入新联系人姓名 - 电话); addButton new QPushButton(添加, this); deleteButton new QPushButton(删除选中, this); actionLayout-addWidget(addEdit); actionLayout-addWidget(addButton); actionLayout-addWidget(deleteButton); // 组合布局 mainLayout-addLayout(searchLayout); mainLayout-addWidget(listView); mainLayout-addLayout(actionLayout); } void MainWindow::setupConnections() { connect(addButton, QPushButton::clicked, this, MainWindow::addContact); connect(deleteButton, QPushButton::clicked, this, MainWindow::deleteContact); connect(searchEdit, QLineEdit::textChanged, this, MainWindow::searchContact); connect(listView, QListView::doubleClicked, this, MainWindow::onItemDoubleClicked); }业务逻辑实现void MainWindow::addContact() { QString contact addEdit-text().trimmed(); if (contact.isEmpty()) { QMessageBox::warning(this, 提示, 请输入联系人信息); return; } // 添加到原始数据 originalData.append(contact); // 根据搜索条件决定显示的数据 QString filterText searchEdit-text(); if (filterText.isEmpty()) { model-setStringList(originalData); } else { searchContact(filterText); } addEdit-clear(); } void MainWindow::deleteContact() { QModelIndexList selectedIndexes listView-selectionModel()-selectedIndexes(); if (selectedIndexes.isEmpty()) { QMessageBox::warning(this, 提示, 请先选择要删除的联系人); return; } // 获取当前显示的数据可能是过滤后的 QStringList currentData model-stringList(); for (const QModelIndex index : selectedIndexes) { QString itemToRemove currentData.at(index.row()); // 从原始数据中移除 originalData.removeAll(itemToRemove); } // 更新显示 searchContact(searchEdit-text()); } void MainWindow::searchContact(const QString text) { if (text.isEmpty()) { model-setStringList(originalData); return; } QStringList filteredData; for (const QString contact : originalData) { if (contact.contains(text, Qt::CaseInsensitive)) { filteredData.append(contact); } } model-setStringList(filteredData); } void MainWindow::onItemDoubleClicked(const QModelIndex index) { QString currentText model-data(index, Qt::DisplayRole).toString(); // 简单的编辑对话框 bool ok; QString newText QInputDialog::getText(this, 编辑联系人, 修改联系人信息:, QLineEdit::Normal, currentText, ok); if (ok !newText.isEmpty()) { // 更新原始数据 int originalIndex originalData.indexOf(currentText); if (originalIndex ! -1) { originalData[originalIndex] newText; searchContact(searchEdit-text()); // 刷新显示 } } }5.4 主函数入口// main.cpp #include MainWindow.h #include QApplication int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWindow window; window.setWindowTitle(通讯录管理系统 - QStringListModel示例); window.resize(400, 500); window.show(); return app.exec(); }6. 高级特性与性能优化6.1 大数据量性能优化当处理大量数据时需要采取优化措施分批加载策略class LargeDataModel : public QStringListModel { public: explicit LargeDataModel(QObject *parent nullptr) : QStringListModel(parent) {} QVariant data(const QModelIndex index, int role Qt::DisplayRole) const override { if (!index.isValid() || index.row() m_data.size()) return QVariant(); // 虚拟化只在需要时加载数据 if (index.row() m_loadedData.size()) { // 这里可以实现按需加载逻辑 loadMoreData(index.row()); } return QStringListModel::data(index, role); } private: void loadMoreData(int requiredIndex) const { // 实现数据分批加载逻辑 // 这里可以连接数据库或文件系统 } mutable QStringList m_loadedData; QStringList m_data; // 全部数据的元信息 };6.2 自定义数据角色除了标准的 DisplayRole还可以使用自定义角色存储额外信息// 定义自定义角色 enum CustomRoles { UserDataRole Qt::UserRole 1, TimestampRole }; // 设置自定义数据 QModelIndex index model-index(0); model-setData(index, QVariant::fromValue(userObject), UserDataRole); model-setData(index, QDateTime::currentDateTime(), TimestampRole); // 读取自定义数据 QVariant userData model-data(index, UserDataRole); UserObject *obj userData.valueUserObject*();6.3 拖拽操作支持实现完整的拖拽功能// 启用拖拽 listView-setDragEnabled(true); listView-setAcceptDrops(true); listView-setDragDropMode(QAbstractItemView::InternalMove); // 自定义拖拽行为 class DragDropModel : public QStringListModel { public: Qt::ItemFlags flags(const QModelIndex index) const override { Qt::ItemFlags defaultFlags QStringListModel::flags(index); if (index.isValid()) return defaultFlags | Qt::ItemIsDragEnabled; else return defaultFlags | Qt::ItemIsDropEnabled; } };7. 常见问题与解决方案7.1 数据同步问题问题现象模型数据更新后视图没有及时刷新解决方案// 确保使用正确的数据更新方法 // 错误做法直接修改底层 QStringList QStringList data model-stringList(); data.append(新项); // 这样修改不会通知视图 // 正确做法通过模型接口修改 model-insertRow(model-rowCount()); model-setData(model-index(model-rowCount()-1), 新项); // 或者批量更新 model-setStringList(newDataList);7.2 选择状态管理问题现象选择项状态异常或无法正确获取选择解决方案// 正确获取选择项 QModelIndexList selectedIndexes listView-selectionModel()-selectedIndexes(); // 处理多选情况 if (!selectedIndexes.isEmpty()) { for (const QModelIndex index : selectedIndexes) { QString selectedText model-data(index, Qt::DisplayRole).toString(); qDebug() 选中项: selectedText; } } // 清空选择 listView-clearSelection();7.3 性能问题排查大数据量卡顿处理// 1. 启用视图优化 listView-setUniformItemSizes(true); // 项大小一致时启用 listView-setLayoutMode(QListView::Batched); // 批量布局更新 // 2. 使用模型重置而不是逐项更新 model-beginResetModel(); // 批量数据更新操作 model-setStringList(largeDataList); model-endResetModel(); // 3. 对于超大数据量考虑使用 QAbstractItemModel 虚拟化8. 最佳实践与工程建议8.1 代码组织规范模型管理最佳实践class ContactManager : public QObject { Q_OBJECT public: explicit ContactManager(QObject *parent nullptr); QStringListModel* model() const { return m_model; } void addContact(const QString contact); void removeContact(int index); void updateContact(int index, const QString newContact); private: QStringListModel *m_model; QStringList m_originalData; }; // 使用独立的模型管理类避免业务逻辑污染界面代码8.2 内存管理建议正确的父子对象关系// 推荐做法设置父对象自动管理内存 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { model new QStringListModel(this); // this 作为父对象 listView new QListView(this); // 当 MainWindow 销毁时子对象自动释放 } // 避免内存泄漏不要混用栈和堆对象8.3 错误处理与健壮性添加数据验证void ContactManager::addContact(const QString contact) { if (contact.trimmed().isEmpty()) { qWarning() 尝试添加空联系人; return; } if (m_originalData.contains(contact)) { qWarning() 联系人已存在: contact; return; } // 数据格式验证 if (!isValidContactFormat(contact)) { qWarning() 联系人格式无效: contact; return; } m_originalData.append(contact); m_model-setStringList(m_originalData); }通过本文的完整学习你应该已经掌握了 QStringListModel 和 QListView 的核心用法。这种模型-视图的设计模式是 Qt 框架的精髓之一理解并熟练运用这种模式将为后续学习更复杂的 Qt 组件打下坚实基础。在实际项目中根据具体需求选择合适的配置选项和优化策略可以构建出既美观又高效的列表界面。

相关新闻

LaTeX环境搭建全攻略:从TeX Live安装到中文排版实战

LaTeX环境搭建全攻略:从TeX Live安装到中文排版实战

1. 项目概述:为什么是LaTeX?如果你还在用Word、WPS这类所见即所得的软件来写论文、报告或者技术文档,尤其是涉及到大量数学公式、交叉引用和复杂排版的时候,我猜你一定经历过格式突然崩溃、编号对不上、或者导师/审稿人一句“格式…

2026/8/1 6:58:27 阅读更多 →
从欧拉路径到de Bruijn序列:图论在DNA测序与密码学中的核心应用

从欧拉路径到de Bruijn序列:图论在DNA测序与密码学中的核心应用

1. 从“一笔画”到“万能钥匙”:欧拉路径与 de Bruijn 序列的奇妙联结如果你玩过“一笔画”游戏,或者对密码学、生物信息学里的序列组装有点兴趣,那你可能已经无意中触碰到了两个听起来很学术,但实际非常有趣的概念:欧…

2026/8/1 6:57:26 阅读更多 →
CRC16校验码:原理、算法实现与嵌入式通信实战

CRC16校验码:原理、算法实现与嵌入式通信实战

1. 项目概述:从校验码到数据守护神 如果你在嵌入式开发、通信协议或者文件传输领域摸爬滚打过,那么“CRC16”这个名词对你来说一定不陌生。它就像一位沉默的哨兵,默默守护着每一串数据在传输或存储过程中的完整性。我最初接触CRC16&#xff0…

2026/8/1 6:57:26 阅读更多 →

最新新闻

从DNS的TTL差异看DNS服务选择的策略

从DNS的TTL差异看DNS服务选择的策略

一、现象:同一域名在不同DNS服务器上的TTL表现迥异在日常网络运维中,我们常会遇到一个有趣的现象:对同一域名(如www.jd.com)使用不同的公共DNS服务器进行解析,返回的TTL(Time to Live&#xff0…

2026/8/1 7:35:01 阅读更多 →
企业级Skill开发与MCP协议架构实战指南

企业级Skill开发与MCP协议架构实战指南

1. 企业级Skill开发的核心价值 在数字化转型浪潮中,企业开发定制化Skill(技能模块)已成为提升业务敏捷性的关键手段。不同于个人开发者的小型技能开发,企业级Skill需要兼顾系统集成、权限管理、审计追踪等复杂需求。以某零售企业为…

2026/8/1 7:35:01 阅读更多 →
计算机毕业设计之基于SpringBoot+Vue的无人超市管理系统的设计与实现

计算机毕业设计之基于SpringBoot+Vue的无人超市管理系统的设计与实现

本文着重研究了一个基于springboot 的无人超市管理系统的开发与实践。文中首先探讨了无人超市管理的关键作用及其在可持续发展方面的重要性,进而论述了采用 VUE框架进行平台开发的理由。文章接着详细介绍了 JAVA语言的优势并讨论了为什么选择 springboot框架来支持 …

2026/8/1 7:35:01 阅读更多 →
MongoDB 8.0——MongoDB的安装

MongoDB 8.0——MongoDB的安装

MongoDB的安装1、在Windows系统上安装MongoDB1.1、安装MongoDB1.2、配置环境变量1.3、其他安装形式1.4、常见问题和注意事项1.4.1、服务无法启动1.4.2、单点发行1.4.3、平台支持1.4.4、虚拟化2、在Linux系统上安装MongoDB2.1、使用yum方式安装MongoDB2.2、卸载MongoDB2.3、使用…

2026/8/1 7:35:01 阅读更多 →
WPS JS宏入门指南:从零到一实现办公自动化

WPS JS宏入门指南:从零到一实现办公自动化

1. 从“手动重复”到“一键完成”:为什么你需要了解WPS JS宏?如果你经常和WPS表格打交道,大概率遇到过这样的场景:每天都要从一堆格式混乱的原始数据里,手动筛选出特定项目,然后复制粘贴到另一个表格&#…

2026/8/1 7:35:01 阅读更多 →
如何快速获取百度网盘提取码:技术爱好者的完整解决方案

如何快速获取百度网盘提取码:技术爱好者的完整解决方案

如何快速获取百度网盘提取码:技术爱好者的完整解决方案 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 还在为百度网盘资源获取而烦恼吗?每次…

2026/8/1 7:34:01 阅读更多 →

日新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/1 0:00:48 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/1 0:00:48 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/1 0:00:48 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/31 1:03:03 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/8/1 5:19:34 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/31 4:19:39 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/1 0:00:48 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/1 0:00:48 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/1 0:00:48 阅读更多 →