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

多层Model更新多层ListView

一、总体架构

QML (三层 ListView)└─ C++ 单例 DataCenter (QQmlContext 注册)├─ L1Model (一级节点)│   └─ 内部持有 QList<L2Model*>│        └─ L2Model (二级节点)│            └─ 内部持有 QList<L3Model*>│                 └─ L3Model (三级节点)
  • 每个 Model 都是 QAbstractListModel 的子类

  • Model 更新后通过 dataChanged() / beginInsertRows() 等标准信号通知 QML

  • DataCenter 为单例,全局只有一个实例

二、文件架构与作用

ThreeLevelListView/
├── main.cpp
├── DataCenter.h / .cpp
├── CountryModel.h / .cpp
├── ProvinceModel.h / .cpp
├── CityModel.h / .cpp
├── qml.qrc
└── main.qml

1.mian.cpp 

作用:注册管理单例,在QML使用DataCenter单例

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "DataCenter.h"int main(int argc, char *argv[])
{QGuiApplication app(argc, argv);QQmlApplicationEngine engine;/* 单例注册 */DataCenter &dc = DataCenter::instance();engine.rootContext()->setContextProperty("DataCenter", &dc);engine.load(QUrl(QStringLiteral("qrc:/main.qml")));return app.exec();
}

2.DataCenter类

作用:管理三级model类,作为QML使用的接口

#ifndef DATACENTER_H
#define DATACENTER_H#include <QObject>
#include "CountryModel.h"class DataCenter : public QObject
{Q_OBJECTQ_PROPERTY(CountryModel* countryModel READ countryModel CONSTANT)
public:static DataCenter* instance(){static DataCenter g_instance;return &g_instance}CountryModel* countryModel() const { return m_countryModel; }private:explicit DataCenter(QObject *parent = nullptr) : QObject(parent), m_countryModel(new CountryModel(this)){}CountryModel *m_countryModel;
};#endif // DATACENTER_H

3.CoutryModel类,继承QAbstractListModel类

作用:第一级Model,管理第二级Model,每一个都有自己的结构提与对应的枚举

struct CountryItem {QString name;ProvinceModel *provinceModel;
};//结构体class CountryModel : public QAbstractListModel
{Q_OBJECT
public:enum Role { NameRole = Qt::UserRole + 1, ObjRole };//及认购提对应枚举
#ifndef COUNTRYMODEL_H
#define COUNTRYMODEL_H#include <QAbstractListModel>
#include "ProvinceModel.h"struct CountryItem {QString name;ProvinceModel *provinceModel;
};class CountryModel : public QAbstractListModel
{Q_OBJECT
public:enum Role { NameRole = Qt::UserRole + 1, ObjRole } : QAbstractListModel(parent) {}explicit CountryModel(QObject *parent = nullptr);//固定函数,函数里面的内容每级不一样int rowCount(const QModelIndex & = QModelIndex()) const override{ return m_items.size(); }QVariant data(const QModelIndex &, int role) const override{if (!index.isValid() || index.row() >= m_items.size()) return QVariant();if (role == NameRole) return m_items.at(index.row()).name;if (role == ObjRole) return QVariant::fromValue(m_items.at(index.row()).provinceModel);return QVariant();}	QHash<int, QByteArray> roleNames() const override{static QHash<int, QByteArray> roles{{NameRole, "name"}, {ObjRole, "obj"}};return roles;}//供QML调用Q_INVOKABLE bool add(const QString &name){beginInsertRows(QModelIndex(), m_items.size(), m_items.size());m_items.append({name, new ProvinceModel(this)});endInsertRows();return true;}Q_INVOKABLE bool remove(int index){if (index < 0 || index >= m_items.size()) return false;beginRemoveRows(QModelIndex(), index, index);delete m_items.takeAt(index).provinceModel;endRemoveRows();return true;
}Q_INVOKABLE bool update(int index, const QString &newName){if (index < 0 || index >= m_items.size()) return false;m_items[index].name = newName;emit dataChanged(createIndex(index, 0), createIndex(index, 0), {NameRole});return true;}Q_INVOKABLE QObject* provinceModelAt(int idx) const{if (idx < 0 || idx >= m_items.size()) return nullptr;return m_items.at(idx).provinceModel;}private:QList<CountryItem> m_items;
};#endif // COUNTRYMODEL_H

4.PrpvinceModel类,继承QAbstractListModel类

作用:第二级Model,管理第三级Model

#ifndef PROVINCEMODEL_H
#define PROVINCEMODEL_H#include <QAbstractListModel>
#include "CityModel.h"struct ProvinceItem {QString name;CityModel *cityModel;
};class ProvinceModel : public QAbstractListModel
{Q_OBJECT
public:enum Role { NameRole = Qt::UserRole + 1, CityModelRole };explicit ProvinceModel(QObject *parent = nullptr) : QAbstractListModel{parent}{}int rowCount(const QModelIndex & = QModelIndex()) const override{return m_items.size();}QVariant data(const QModelIndex &, int role) const override{if (!index.isValid() || index.row() >= m_items.size()) return QVariant();if (role == NameRole) return m_items.at(index.row()).name;if (role == CityModelRole) return QVariant::fromValue(m_items.at(index.row()).cityModel);return QVariant();}QHash<int, QByteArray> roleNames() const override{static QHash<int, QByteArray> roles{{NameRole, "name"}, {CityModelRole, "obj"}};return roles;}Q_INVOKABLE bool add(const QString &name){beginInsertRows(QModelIndex(), m_items.size(), m_items.size());m_items.append({name, new CityModel(this)});endInsertRows();return true;}Q_INVOKABLE bool remove(int index){if (index < 0 || index >= m_items.size()) return false;beginRemoveRows(QModelIndex(), index, index);delete m_items.takeAt(index).cityModel;endRemoveRows();return true;}Q_INVOKABLE bool update(int index, const QString &newName){if (index < 0 || index >= m_items.size()) return false;m_items[index].name = newName;emit dataChanged(createIndex(index, 0), createIndex(index, 0), {NameRole});return true;}Q_INVOKABLE QObject* cityModelAt(int idx) const{if (idx < 0 || idx >= m_items.size()) return nullptr;return m_items.at(idx).cityModel;}private:QList<ProvinceItem> m_items;
};#endif // PROVINCEMODEL_H

5.CityModel类,继承QAbstractListModel类

作用:第三级Model,管理自己的成员

#ifndef CITYMODEL_H
#define CITYMODEL_H#include <QAbstractListModel>struct CityItem {QString name;
};class CityModel : public QAbstractListModel
{Q_OBJECT
public:enum Role { NameRole = Qt::UserRole + 1, };explicit CityModel(QObject *parent = nullptr): QAbstractListModel{parent}{}int rowCount(const QModelIndex & = QModelIndex()) const override{return m_items.size();}QVariant data(const QModelIndex &, int role) const override{if (!index.isValid() || index.row() >= m_items.size()) return QVariant();if (role == NameRole) return m_items.at(index.row()).name;//if (role == CityModelRole) return QVariant::fromValue(m_items.at(index.row()).cityModel);return QVariant();}QHash<int, QByteArray> roleNames() const override{//static QHash<int, QByteArray> roles{{NameRole, "name"}, {CityModelRole, "obj"}};static QHash<int, QByteArray> roles{{NameRole, "name"}, };return roles;}Q_INVOKABLE bool add(const QString &name){beginInsertRows(QModelIndex(), m_items.size(), m_items.size());m_items.append({name});endInsertRows();return true;}Q_INVOKABLE bool remove(int index){if (index < 0 || index >= m_items.size()) return false;beginRemoveRows(QModelIndex(), index, index);m_items.takeAt(index);endRemoveRows();return true;}Q_INVOKABLE bool update(int index, const QString &newName){if (index < 0 || index >= m_items.size()) return false;m_items[index].name = newName;emit dataChanged(createIndex(index, 0), createIndex(index, 0), {NameRole});return true;}private:QList<CityItem> m_items;
};#endif // CITYMODEL_H

6.mian.qml

作用:显示界面

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15Window {visible: truewidth: 1000;height: 600title: "3 级嵌套 Model 示例"RowLayout {anchors.fill: parentanchors.margins: 10spacing: 10/* ---------- Level 1 : Country ---------- */ColumnLayout {Layout.fillWidth: trueLabel { text: "国家"; font.bold: true }ListView {id: lvCountryLayout.fillHeight: true; Layout.fillWidth: truemodel: DataCenter.countryModeldelegate: Rectangle {width: lvCountry.width; height: 30color: (lvCountry.currentIndex === index) ? "lightblue" : "white"Text { text: name; anchors.centerIn: parent }MouseArea {anchors.fill: parentonClicked: lvCountry.currentIndex = index}}currentIndex: -1}TextField { id: tfCountry; Layout.fillWidth: true; placeholderText: "输入国家" }RowLayout {Button { text: "添加"; onClicked:{ DataCenter.countryModel.add(tfCountry.text); tfCountry.clear() }}Button { text: "删除"; enabled: lvCountry.currentIndex>=0;onClicked: DataCenter.countryModel.remove(lvCountry.currentIndex) }Button { text: "修改"; enabled: lvCountry.currentIndex>=0;onClicked: DataCenter.countryModel.update(lvCountry.currentIndex, tfCountry.text) }}}/* ---------- Level 2 : Province ---------- */ColumnLayout {Layout.fillWidth: trueLabel { text: "省份"; font.bold: true }ListView {id: lvProvinceLayout.fillHeight: true; Layout.fillWidth: truemodel: lvCountry.currentIndex >= 0? DataCenter.countryModel.provinceModelAt(lvCountry.currentIndex): nulldelegate: Rectangle {width: lvProvince.width; height: 30color: (lvProvince.currentIndex === index) ? "lightblue" : "white"Text { text: name; anchors.centerIn: parent }MouseArea {anchors.fill: parentonClicked: lvProvince.currentIndex = index}}currentIndex: -1}TextField { id: tfProvince; Layout.fillWidth: true; placeholderText: "输入省份" }RowLayout {Button { text: "添加"; enabled: lvCountry.currentIndex>=0;onClicked: { lvProvince.model.add(tfProvince.text); tfProvince.clear() } }Button { text: "删除"; enabled: lvProvince.currentIndex>=0;onClicked: lvProvince.model.remove(lvProvince.currentIndex) }Button { text: "修改"; enabled: lvProvince.currentIndex>=0;onClicked: lvProvince.model.update(lvProvince.currentIndex, tfProvince.text) }}}/* ---------- Level 3 : City ---------- */ColumnLayout {Layout.fillWidth: trueLabel { text: "市"; font.bold: true }ListView {id: lvCityLayout.fillHeight: true; Layout.fillWidth: truemodel: lvProvince.currentIndex >= 0? lvProvince.model.cityModelAt(lvProvince.currentIndex): nulldelegate: Rectangle {width: lvCity.width; height: 30color: (lvCity.currentIndex === index) ? "lightblue" : "white"Text { text: name; anchors.centerIn: parent }MouseArea {anchors.fill: parentonClicked: lvCity.currentIndex = index}}currentIndex: -1}TextField { id: tfCity; Layout.fillWidth: true; placeholderText: "输入市" }RowLayout {Button { text: "添加"; enabled: lvProvince.currentIndex>=0;onClicked: { lvCity.model.add(tfCity.text); tfCity.clear() } }Button { text: "删除"; enabled: lvCity.currentIndex>=0;onClicked: lvCity.model.remove(lvCity.currentIndex) }Button { text: "修改"; enabled: lvCity.currentIndex>=0;onClicked: lvCity.model.update(lvCity.currentIndex, tfCity.text) }}}}
}

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

相关文章:

  • 4. 什么是字节码采用字节码的好处是什么
  • avue---upload 图片上传
  • 南柯电子|直流电机EMC整改:从干扰源到解决方案的实战指南
  • DHCP 握手原理
  • Laravel The requested URL /hellowzy was not found on this server. 404 问题的解决
  • gRPC Keepalive 机制详解与最佳实践
  • 本地部署文档管理平台 BookStack 并实现外部访问( Windows 版本)
  • C# LINQ(标准询运算符)
  • Windows 电脑远程访问,ZeroTier 实现内网穿透完整指南(含原理讲解)
  • 汽车OBD定位器:即插即用车辆管理省心又实用
  • CodeBuddy IDE 使用测评——半小时做一个web可视化数据工具
  • 数据可视化发展历程
  • eclipse类IDE导入现有工程教程
  • 分布式CAP定理
  • Java 中抽象概念的全面解析与实战指南
  • Python爬虫09_Requests用bs4进行数据解析
  • 【科研绘图系列】R语言绘制误差棒图
  • 【C++】模板深入进阶
  • 通信算法之298: verilog语法generate和for介绍
  • 深入浅出:Ajax 与 Servlet 实现前后端数据交互
  • VUE+SPRINGBOOT从0-1打造前后端-前后台系统-登录实现
  • 平面设计软件PS+AI百度云网盘资源在线观看
  • 读者提问:如果维度退化或下沉的维度属性发生了变化,事实表该如何处理?
  • 技术与情感交织的一生 (十一)
  • spring循环依赖解决
  • 一(3)理解 newNode->next = head 和 Node* temp = head 的区别
  • UF_MODL_ask_curve_points 离散曲线,按长度分段曲线,不准确 不知道为啥
  • 面向对象的七大设计原则
  • 【音视频】WebRTC 一对一通话-信令服
  • 【计算机网络】6应用层