QML < 6 > C++ 向QML 传递复杂数据结构 TableView 使用C++ Model QAbstractTableModel_qml tableview qabstracttablemodel-程序员宅基地

技术标签: QML  c++  开发语言  

QML < 6 > C++ 向QML 传递复杂数据结构 TableView 使用C++ Model QAbstractTableModel

前言

TableView 表格显示常用控件,使用C++ model 便于处理复杂的数据结构,也更利于数据和UI 解耦 ,
本文记录下 Tableview 使用C++ model示例,使用Model 为QAbstractTableModel。
表格数据和样式参照之前文章:QML <4> Tableview 自定义表格显示 delegate FontAwesome Canvas

一、QAbstractTableModel 类自定义 CustomDataModel

1数据格式

数据源JSON 数组格式,如下:

2数据结构定义

struct Music_Data
{
    
    bool NewFlag;
    bool TrendUp;
    int TrendNum;
    QString ImageSouce;
    QString Title;
    int Time;
    QString Singer;
};
   QVector< Music_Data> vDatas;

3 数据结构字段对应枚举声明

Q_ENUMS(EM_DATA_ROLE)
 enum  EM_DATA_ROLE
  {
    
      Data_Role_NewFlag = Qt::UserRole+1,
      Data_Role_TrendUp,
      Data_Role_TrendNum,
      Data_Role_ImageSouce,
      Data_Role_Title,
      Data_Role_Time,
      Data_Role_Singer
  };

4 重写rowCount

rowCount函数返回 表格行数,代码如下:

int CustomDataModel::rowCount(const QModelIndex &parent) const
{
    
     Q_UNUSED(parent);
    return vDatas.size();
}

5 重写columnCount

columnCount 函数返回表格列数,本文中表格列在QML 中TableView 定义,model 实现函数如下,

QStringlist head << QStringLiteral("")<< QStringLiteral("标题")<<QStringLiteral("时长")<< QStringLiteral("歌手");
int CustomDataModel::columnCount(const QModelIndex &parent) const
{
    
     Q_UNUSED(parent);
   return head.size();
}

6 重写roleNames

roleNames 函数返回表格列role QML TableView 列定义相同Role ,根据Role 匹配获取表格单元格数据,代码如下:

QHash<int, QByteArray> CustomDataModel::roleNames() const
{
    
    QHash<int, QByteArray> roles;
    roles[Data_Role_NewFlag] = "NewFlag";
    roles[Data_Role_Title] = "Title";
    roles[Data_Role_Time] = "Time";
    roles[Data_Role_ImageSouce] = "ImageSouce";
    roles[Data_Role_TrendNum] = "TrendNum";
    roles[Data_Role_TrendUp] = "TrendUp";
    roles[Data_Role_Singer] = "Singer";
    return roles;
}

7 重写data

QML TableView 更新但与个数据时调用data函数,根据Role 返回对应数据,代码如下:

QVariant CustomDataModel::data(const QModelIndex &index, int role) const
{
    
    if(index.row() >= vDatas.size())
    {
    
        return QVariant();
    }

    const  Music_Data  rowData  = vDatas.at(index.row());
    switch(role)
    {
    
    case Data_Role_NewFlag:
    {
    
        return rowData.NewFlag;
    }break;
    case Data_Role_Time:
    {
    
        return rowData.Time;
    }break;
    case Data_Role_Title:
    {
    
        return rowData.Title;
    }break;
    case Data_Role_Singer:
    {
    
        return rowData.Singer;
    }break;
    case Data_Role_ImageSouce:
    {
    
        return rowData.ImageSouce;
    }break;
    case Data_Role_TrendNum:
    {
    
        return rowData.TrendNum;
    }break;
    case Data_Role_TrendUp:
    {
    
        return rowData.TrendUp;
    }break;
    default: return QVariant();
    }
}

8 定义自定义函数getDataFromRowByRole

getDataFromRowByRole 获取指定行指定列Role 数据,自定义函数要在QML 中调用 函数声明需要添加Q_INVOKABLE,代码如下:

 Q_INVOKABLE QVariant getDataFromRowByRole(int row ,int role);
 QVariant CustomDataModel::getDataFromRowByRole(int row, int role)
{
    

    QVariant data;
    if(row < vDatas.size())
    {
    
        Music_Data row_data = vDatas.at(row);

        switch(role)
        {
    
        case Data_Role_NewFlag:{
     data=  QVariant::fromValue(row_data.NewFlag);}break;
        case Data_Role_TrendUp:{
     data=  QVariant::fromValue(row_data.TrendUp);}break;
        case Data_Role_TrendNum:{
     data=  QVariant::fromValue(row_data.TrendNum);}break;
        case Data_Role_ImageSouce:{
     data=  QVariant::fromValue(row_data.ImageSouce);}break;
        case Data_Role_Title:{
     data=  QVariant::fromValue(row_data.Title);}break;
        case Data_Role_Time:{
     data=  QVariant::fromValue(row_data.Time);}break;
        case Data_Role_Singer:{
     data=  QVariant::fromValue(row_data.Singer);}break;
        }
    }
    return data;
}

二、Model 注册到QML

C++ 类在QML 中调用,需要将C++ 类注册到QML,注册方式有两种,一种是注册类类型,一种是注册类实例,本文注册C++ 类如下:

  qmlRegisterType<CustomDataModel>("CustomDataModel",1, 0, "CustomDataModel");

QML 使用如下:

import CustomDataModel 1.0
 CustomDataModel
    {
    
        id:tablemodel;
    }

三、Model 的数据和TableView 列一一对应

TableView根据Model 数据显示,不对数据做任何处理。TableView 定义如下:

    TableView {
    

        anchors.fill: parent


        TableViewColumn {
    title: "NewFlag"; role: "NewFlag"; width: 70 }

        TableViewColumn {
    title: "Title"; role: "Title"; width: 70   }
        TableViewColumn {
    title: "Time"; role: "Time"; width: 70 }
        TableViewColumn {
    title: "ImageSouce"; role: "ImageSouce"; width: 70   }
        TableViewColumn {
    title: "TrendNum"; role: "TrendNum"; width: 70 }
        TableViewColumn {
    title: "TrendUp"; role: "TrendUp"; width: 70   }
        TableViewColumn {
    title: "Singer"; role: "Singer"; width: 70 }
        model: tablemodel
    }

代码运行效果如下:
在这里插入图片描述

四、Model 的列数据Role和TableView 列Role有差别

在QML 中调用getDataFromRowByRole 获取当前表格更新行数据,并设置相应变量

1 TableView 定义

CustomDataModel
    {
    
        id:tablemodel;
    }

    TableView
    {
    
        id:tableview
        anchors.fill: parent
        TableViewColumn{
    role: "NewFlag"; title: ""; width: 80; elideMode: Text.ElideRight;}
        TableViewColumn{
    role: "Title"; title: qsTr("标题"); width: 320; elideMode: Text.ElideRight;}
       TableViewColumn{
    role: "Time"; title: qsTr("时长"); width: 90;}
        TableViewColumn{
    role: "Singer"; title: qsTr("歌手"); width: 120;}
        headerDelegate:header_delegate
        itemDelegate:  item_delegate
        rowDelegate: Rectangle
        {
    
            height: styleData.row < 3 ?image_row_height:row_height;
            //border.color:"gray";
            //color: styleData.alternate?"lightgray":"white"
        }

        model:tablemodel

    }

2 排行delegate 数据

变量赋值方式:

 property var new_flag :
                        {
    
                          var data = tablemodel.getDataFromRowByRole(styleData.row,CustomDataModel.Data_Role_NewFlag)
                          return data
                         }

在这里插入图片描述

3 标题delegate数据

在这里插入图片描述

4 时长delegate数据

在这里插入图片描述

5 歌手delegate数据

在这里插入图片描述

6 运行效果

在这里插入图片描述

总结

1 json 数据解析

void CustomDataModel::parseJsonData()
{
    
   
    const QString  filepath = ":/data/music_data.json";

    QFile file(filepath);
    if(!file.exists())
    {
    
        return ;
    }
    if(!file.open(QFile::ReadOnly))
    {
    
        return;
    }
    QByteArray  jsonstr = file.readAll();


    QJsonParseError parseerror;
    QJsonDocument doc = QJsonDocument::fromJson(jsonstr,&parseerror);
    if(parseerror.error !=  QJsonParseError::NoError)
    {
    
        qDebug() <<"parseerror";
        return;
    }
    QJsonObject obj = doc.object();

    QJsonArray data = obj["Data"].toArray();

    foreach(auto item , data)
    {
    
        Music_Data  data;
        data.Time =item["Time"].toInt() ;
        data.NewFlag= item["NewFlag"].toBool();
        data.TrendUp=item["TrendUp"].toBool();
        data.TrendNum=item["TrendNum"].toInt();
        data.ImageSouce=item["ImageSouce"].toString();
        data.Singer=item["Singer"].toString();
        data.Title=item["Title"].toString();
        vDatas.push_back(data);
    }
}

2 自定义model 踩坑

实现自定义model的时候不要实现,实现后造成data函数
不调用,最开始基类 选择的QAbstractItemModel 这两个函数是必须要实现,这里先贴出当时实现后不调用data函数时的代码,待后面分析原因,

virtual QModelIndex index(int row, int column,
                             const QModelIndex &parent = QModelIndex()) const ;
QModelIndex CustomDataModel::index(int row, int column, const QModelIndex &parent) const
{
    
   return  QModelIndex();
}
virtual QModelIndex parent(const QModelIndex &child) const ;
QModelIndex CustomDataModel::parent(const QModelIndex &child) const
{
    
    Q_UNUSED(child);
    return QModelIndex();
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jiang173707/article/details/121780307

智能推荐

python色卡识别_用Python帮小姐姐选口红,人人都是李佳琦-程序员宅基地

文章浏览阅读502次。原标题:用Python帮小姐姐选口红,人人都是李佳琦 对于李佳琦,想必知道他的女生要远远多于男生,李佳琦最早由于直播向广大的网友们推荐口红,逐渐走红网络,被大家称作“口红一哥”。不可否认的是,李佳琦的直播能力确实很强,他能够抓住绝大多数人的心理,让大家喜欢看他的直播,看他直播推荐的口红适不适合自己,色号适合什么样子的妆容。为了提升效率,让自己的家人或者女友能够快速的挑选出合适自己妆容的口红色号,今..._获取口红品牌 及色号,色值api

linux awk命令NR详解,linux awk命令详解-程序员宅基地

文章浏览阅读3.6k次。简介awk命令的名称是取自三位创始人Alfred Aho 、Peter Weinberger 和 Brian Kernighan姓名的首字母,awk有自己的程序设计语言,设计简短的程序,读入文件,数据排序,处理数据,生成报表等功能。awk 通常用于文本处理和报表生成,最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。awk 通常以文件的一行为处理单位..._linux awk nr

android 网络连接失败!failed to connect to /192.168.1.186(port 8080)_failed to connect to 192.168.88.218:80-程序员宅基地

文章浏览阅读1.3w次,点赞5次,收藏2次。在网上找了一个小时,一直没有头绪,因为上个星期还是好好的,最后看到一个大神的解答,只需要将防火墙关闭就好了.原本向测试功能的,却卡在了登录上.以此记录.另外好像还有种错误是电脑与手机连接的WiFi不同,也可以看看...._failed to connect to 192.168.88.218:80

matlab 多径衰落,利用MATLAB仿真多径衰落信道.doc-程序员宅基地

文章浏览阅读1.9k次。利用MATLAB仿真多种多径衰落信道摘要:移动信道的多径传播引起的瑞利衰落,时延扩展以及伴随接收过程的多普勒频移使接受信号受到严重的衰落,阴影效应会是接受的的信号过弱而造成通信的中断:在信道中存在噪声和干扰,也会是接收信号失真而造成误码,所以通过仿真找到衰落的原因并采取一些信号处理技术来改善信号接收质量显得很重要,这里利用MATLAB对多径衰落信道的波形做一比较。一,多径衰落信道的特点关于多径衰落..._matlab多径衰落工具箱

python对json的操作及实例解析_import json灰色-程序员宅基地

文章浏览阅读1w次,点赞2次,收藏17次。Json简介:Json,全名 JavaScript Object Notation,是一种轻量级的数据交换格式。它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。(来自百度百科)python关于json文_import json灰色

mysql实现MHA高可用详细步骤_mysql mha超详细教程-程序员宅基地

文章浏览阅读1.1k次,点赞6次,收藏3次。一、工作原理MHA工作原理总结为以下几条:(1) 从宕机崩溃的 master 保存二进制日志事件(binlog events);(2) 识别含有最新更新的 slave ;(3) 应用差异的中继日志(relay log) 到其他 slave ;(4) 应用从 master 保存的二进制日志事件(binlog events);(5) 通过Manager控制器提升一个 slave 为新 m..._mysql mha超详细教程

随便推点

Linux环境下主从搭建心得(高手勿喷)_linux的java主从策略是什么-程序员宅基地

文章浏览阅读194次。一 java环境安装:1 安装JDK 参考链接地址:https://blog.csdn.net/qq_42815754/article/details/82968464注:有网情况下直接 yum 一键安装:yum -y list java(1)首先执行以下命令查看可安装的jdk版本(2)选择自己需要的jdk版本进行安装,比如这里安装1.8,执行以下命令:yum install -y java-1.8.0-openjdk-devel.x86_64(3)安装完之后,查看安装的jdk 版本,输入以下指令_linux的java主从策略是什么

ACM第四题_acm竞赛题 i 'm from mars-程序员宅基地

文章浏览阅读104次。定义int 类型,由while实现A,B的连续输入,输出A+B的值按Ctrl Z结束循环。#include&amp;lt;iostream&amp;gt;using namespace std;int main(){ int A,B; while(cin&amp;gt;&amp;gt;A&amp;gt;&amp;gt;B) { cout&amp;lt;&amp;lt;A+B&amp;lt;&_acm竞赛题 i 'm from mars

TextView.SetLinkMovementMethod后拦截所有点击事件的原因以及解决方法-程序员宅基地

文章浏览阅读5.2k次。在需要给TextView的某句话添加点击事件的时候,我们一般会使用ClickableSpan来进行富文本编辑。与此同时我们还需要配合 textView.setMovementMethod(LinkMovementMethod.getInstance());方法才能使点击处理生效。但与此同时还会有一个问题:如果我们给父布局添加一个点击事件,需要在点击非链接的时候触发(例如RectclerV..._linkmovementmethod

JAVA实现压缩解压文件_java 解压zip-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏31次。JAVA实现压缩解压文件_java 解压zip

JDK8 新特性-Map对key和value分别排序实现_java comparingbykey-程序员宅基地

文章浏览阅读1.3w次,点赞7次,收藏21次。在Java 8 中使用Stream 例子对一个 Map 进行按照keys或者values排序.1. 快速入门 在java 8中按照此步骤对map进行排序.将 Map 转换为 Stream 对其进行排序 Collect and return a new LinkedHashMap (保持顺序)Map result = map.entrySet().stream() .sort..._java comparingbykey

GDKOI2021普及Day1总结-程序员宅基地

文章浏览阅读497次。第一次参加GDKOI,考完感觉还可以,结果发现还是不行,有一些地方细节打错,有些失分严重,总结出以下几点:1.大模拟一定要注意,细节打挂就是没分,像T1就是一道大模拟题,马上切了,后面就没想着检查以下,导致有些地方挂掉了,用民间数据一测,才85分。2.十年OI一场空,不开longlonglong longlonglong见祖宗。今天的T2本来想用暴力水点分的,结果没想到longlong→intlong long\to intlonglong→int,40→040\to040→0。3.代码实现能力太差,_gdkoi

推荐文章

热门文章

相关标签