多層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.pswp.cn/web/92032.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/92032.shtml
英文地址,請注明出處:http://en.pswp.cn/web/92032.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Git基礎操作教程

本文目的是掌握Git基礎操作教程一、Git簡介Git&#xff1a;分布式版本控制系統&#xff0c;使用倉庫(Repository)來記錄文件的變化最流行的版本控制系統有兩種&#xff1a;集中式&#xff08;SVN&#xff09;、分布式&#xff08;Git&#xff09;二、Git操作1.創建倉庫倉庫(Rep…

Android 之 Kotlin

變量變量的聲明Kotlin使用var&#xff0c;val來聲明變量&#xff0c;注意&#xff1a;Kotlin不再需要;來結尾var 可變變量&#xff0c;對應java的非final變量var b 1val不可變變量&#xff0c;對應java的final變量val a 1兩種變量并未聲明類型&#xff0c;這是因為Kotlin存在…

Design Compiler:布圖規劃探索(ICC)

相關閱讀 Design Compilerhttps://blog.csdn.net/weixin_45791458/category_12738116.html?spm1001.2014.3001.5482 簡介 在Design Compiler Graphical中&#xff0c;可以用布圖規劃探索(Floorplan Exploration)功能&#xff0c;打開IC Compiler進行布圖規劃的創建、修改與分…

《藍牙低功耗音頻技術架構解析》

《2025GAS聲學大講堂—音頻產業創新技術公益講座》低功耗藍牙音頻系列專題LE Audio & Auracast?專題講座第1講將于8月7日周四19點開講&#xff0c;本次邀請了藍牙技術聯盟 技術與市場經理 魯公羽 演講&#xff0c;講座主題&#xff1a;《藍牙低功耗音頻技術架構解析》。&…

ubuntu apt安裝與dpkg安裝相互之間的關系

0. 問題解釋 在linux系統中&#xff0c;使用neofetch命令可以看到現在系統中使用dpkg, flatpak, snap安裝的包的數量&#xff0c;那么使用apt安裝的包被統計在什么位置了呢&#xff0c;使用apt的安裝流程和使用flatpak的安裝流程有什么關系和區別呢?1. apt 安裝的包在哪里&…

YooAsset源碼閱讀-Downloader篇

YooAsset源碼閱讀-Downloader 繼續 YooAsset 的 Downloader &#xff0c;本文將詳細介紹如何創建下載器相關代碼 CreateResourceDownloaderByAll 關鍵類 PlayModeImpl.csResourceDownloaderOperation.csDownloaderOperation.csBundleInfo.cs CreateResourceDownloaderByAll 方法…

豆包新模型與 PromptPilot 實操體驗測評,AI 輔助創作的新范式探索

摘要&#xff1a;在 AI 技術飛速發展的當下&#xff0c;各類大模型及輔助工具層出不窮&#xff0c;為開發者和創作者帶來了全新的體驗。2025 年 7 月 30 日廈門站的火山方舟線下 Meetup&#xff0c;為我們提供了近距離接觸豆包新模型與 PromptPilot 的機會。本次重點體驗了實驗…

深入探討AI在測試領域的三大核心應用:自動化測試框架、智能缺陷檢測和A/B測試優化,并通過代碼示例、流程圖和圖表詳細解析其實現原理和應用場景。

引言隨著人工智能技術的飛速發展&#xff0c;軟件測試領域正在經歷一場深刻的變革。AI技術不僅提高了測試效率&#xff0c;還增強了測試的準確性和覆蓋范圍。本文將深入探討AI在測試領域的三大核心應用&#xff1a;自動化測試框架、智能缺陷檢測和A/B測試優化&#xff0c;并通過…

音視頻學習筆記

0.vs應用其他庫配置1基礎 1.1視頻基礎 音視頻錄制原理音視頻播放原理圖像表示rgb圖像表示yuvhttps://blog.51cto.com/u_7335580/2059670 https://blog.51cto.com/cto521/1944224 https://blog.csdn.net/mandagod/article/details/78605586?locationNum7&fps1 視頻主要概念…

LLM隱藏層狀態: outputs.hidden_states 是 MLP Residual 還是 Layer Norm

outputs.hidden_states 是 MLP Residual 還是 Layer Norm outputs.hidden_states 既不是單純的 MLP Residual,也不是單純的 Layer Norm,而是每一層所有組件(包括 Layer Norm、注意力、MLP、殘差連接等)處理后的最終隱藏狀態。具體需結合 Transformer 層的結構理解: 1. T…

XML 用途

XML 用途 引言 XML&#xff08;可擴展標記語言&#xff09;是一種用于存儲和傳輸數據的標記語言。自1998年推出以來&#xff0c;XML因其靈活性和可擴展性&#xff0c;在眾多領域得到了廣泛應用。本文將詳細介紹XML的用途&#xff0c;幫助讀者全面了解這一重要技術。 一、數據存…

亞馬遜撤離Google購物廣告:重構流量生態的戰略博弈

戰略突變&#xff1a;從漸進收縮到全面退潮的背后邏輯亞馬遜在2025年7月突然全面停止Google Shopping廣告投放&#xff0c;這場看似 abrupt 的決策實則經歷了一年多的戰略鋪墊&#xff0c;從2024年Q1開始的預算削減&#xff0c;到2025年Q2美國市場支出減半&#xff0c;直至核心…

【QT】常?控件詳解(三)常用按鈕控件PushButton RadioButton CheckButton Tool Button

文章目錄前言一、PushButton1.1 QAbstractButton1.2 添加圖標的按鈕1.3 給按鈕添加快捷鍵1.4 代碼?例:按鈕的重復觸發二、 RadioButtion2.1簡介2.2 幾個槽函數 click,press,release, toggled 的區別2.2 模擬分組點餐三、 CheckBox四、Tool Button&#x1f6a9;總結前言 一、P…

數據結構:反轉鏈表(reverse the linked list)

目錄 通過交換元素值實現反轉&#xff08;reverse by swapping elements&#xff09; 滑動指針&#xff08;sliding pointers&#xff09; 使用滑動指針反轉鏈表&#xff08;Reversing a Linked List using Sliding Pointers&#xff09; 對比分析 如何用遞歸&#xff08;R…

【C#】基于SharpCompress實現壓縮包解壓功能

1.SharpCompress安裝 在vs的nuget下搜索安裝SharpCompress&#xff0c;如圖所示2.解壓縮包功能實現 /// <summary> /// 解壓壓縮包 /// </summary> /// <param name"filePath">壓縮包文件路徑</param> /// <param name"directoryPat…

mybatis連接PGSQL中對于json和jsonb的處理方法

pgsql數據庫表字段設置了jsonb格式&#xff1b;在java的實體里使用String或者對象轉換會一直提示一個錯誤&#xff1a; Caused by: org.postgresql.util.PSQLException: ERROR: column “xx” is of type jsonb but expression is of type character varying 需要加一個轉換方法…

Spring AI Alibaba Graph 深度解析:原理、架構與應用實踐

1. 引言概述 1.1 什么是 Spring AI Alibaba Graph Spring AI Alibaba Graph 是阿里云團隊基于 Spring AI 生態開發的一個強大的工作流編排框架&#xff0c;專門用于構建復雜的 AI 應用。它采用聲明式編程模型&#xff0c;通過圖結構來定義和管理 AI 工作流&#xff0c;讓開發…

C++少兒編程(二十一)—軟件執行流程

讓我們將以下程序視為用C編寫的示例程序。步驟1&#xff1a;預處理器將源代碼轉換為擴展代碼。當您運行程序時&#xff0c;源代碼首先被發送到稱為預處理器的工具。預處理器主要做兩件事&#xff1a;它會從程序中刪除注釋。它擴展了預處理器指令&#xff0c;如宏或文件包含。它…

精通Webpack搭建Vue2.0項目腳手架指南

本文還有配套的精品資源&#xff0c;點擊獲取 簡介&#xff1a;在Web應用程序開發中&#xff0c;Vue 2.0因其虛擬DOM、單文件組件、增強的生命周期鉤子和Vuex及Vue Router狀態管理與路由解決方案&#xff0c;成為了提高開發效率和代碼組織性的關鍵。Webpack作為必不可少的模…

無償分享120套開源數據可視化大屏H5模板

數據可視化跨越了語言、技術和專業的邊界&#xff0c;是能夠推動實現跨界溝通&#xff0c;實現國際間跨行業的創新的工具。正如畫家用顏料表達自我&#xff0c;作者用文字講述故事&#xff0c;而統計人員用數字溝通 ...... 同樣&#xff0c;數據可視化的核心還是傳達信息。而設…