QML APP开发套路(三):前/后端值传递(自定义值类型)

(1)前/后端交互内容

QML APP前后端交互的内容按目标(拍脑袋)可以分为2个部分:

方向内容
后端(C++) → 前端(QML)前端展示所需的数据,形式:简单类型、列表、详情
前端(QML) → 后端(C++)后端获取数据所需的参数,形式:简单类型、对象

但是,问题来了:前后端怎么互认数据形式(数格格式、数据类型)?
官方文档 Data Type Conversion Between QML and C++ 介绍得比较全面,不再赘述。
作者小结(再次拍脑袋)QML与C++之间的类型转换可为5个部分:

  1. 简单类型,如:bool、int、QString、QDateTime等QT C++类型与QML基本对应
  2. 枚举类型,使用Q_ENUM标记后对应QML的enum类型
  3. 对象类型,QVariantMap、QJsonObject类型对应 js 对象类型
  4. 序列类型,QVariantList、QList<…>、QStringList等类型对应json数组类型
  5. 自定义值类型,对应 js 对象类型;使用QVariantList、QList包装后则对应json数组类型

可见,相比C++,QML所支持的类型较为简单,除了简单类型和枚举类型,就是json对象和json数组。

(2)定义类型
(2.1)自定义值类型
  1. 使用 Q_GADGET 宏进行注释(视为QObject的简化,不能有信号和槽,可以有属性和方法)
  2. 使用 Q_PROPERTY 定义属性以及 getter 和 setter 方法
  3. 使用 Q_DECLARE_METATYPE 标记类型

示例如下:

class AtlasCat {
   Q_GADGET
   Q_PROPERTY(int code READ getCode WRITE setCode)
   Q_PROPERTY(QString title READ getTitle WRITE setTitle)
   Q_PROPERTY(int dispno READ getDispno WRITE setDispno)
   Q_PROPERTY(int level READ getLevel WRITE setLevel)
   Q_PROPERTY(int parentCode READ getParentCode WRITE setParentCode)

public:
   explicit AtlasCat();
   ~AtlasCat();

   // getter|setter

   int getCode() const { return (m_code); }
   void setCode(const int code) { this->m_code = code; }

   QString getTitle() const { return (m_title); }
   void setTitle(const QString &title) { this->m_title = title; }

   int getDispno() const { return (m_dispno); }
   void setDispno(const int dispno) { this->m_dispno = dispno; }

   int getLevel() const { return (m_level); }
   void setLevel(const int level) { this->m_level = level; }

   int getParentCode() const { return (m_parentCode); }
   void setParentCode(const int parentCode) { this->m_parentCode = parentCode; }

private:

   int m_code = -1;
   QString m_title;
   int m_dispno = -1;
   int m_level = -1;
   int m_parentCode = -1;
};
Q_DECLARE_METATYPE(AtlasCat)
(2.2)自定义枚举类型
/** Gender */
enum Gender {
   Male = 0, //Male
   Female = 1, //Female
};
Q_ENUM(Gender)
(3)值传递
(3.1)后端 → 前端
  1. 业务对象的定义
    以下是相关业务对象所定义的属性,其中引用到了2.1中的自定义类型:
    /** 分类列表|前端读 */
    Q_PROPERTY(QVariantList atlasCatList READ getAtlasCatList NOTIFY atlasCatListChanged)
    /** 所选分类|前端读写 */
    Q_PROPERTY(AtlasCat atlasCat READ getAtlasCat NOTIFY atlasCatChanged)

  实际上,属性【atlasCatList】亦可用QList<AtlasCat>类型。

  1. 业务对象传值处理
    AtlasCat cat1;
        cat4.setCode(101);
        cat4.setTitle("aaaa");
        cat4.setDispno(1);
        cat4.setLevel(1);
        cat4.setParentCode(m_atlas);

    this->m_atlasCatList.clear();
    this->m_atlasCatList.append(QVariant::fromValue(cat1));
    ...
    emit atlasCatListChanged();

 在准备好数据之后,即通知前端进行获取。

  1. 前端(QML)接收并解析
    在QML的业务对象的信号回调处理函数中对所传值进行接收和解析。
AtlasManObj {
    id: atlasManObj1
    ...
    onAtlasCatListChanged: {
        console.log("FRONTEND RETURNS @ onAtlasCatListChanged");

        var list1 = atlasManObj1.getAtlasCatList();
        for(var i in list1) {
            console.log("item #" + (parseInt(i)+1) + " = {" + list1[i] + " }")
        }
    }
    ...

输出如下:

qml: FRONTEND RETURNS @ onAtlasCatListChanged
qml: item #1 = {AtlasCat(101, aaaa, 1, 1, 0) }
qml: item #2 = {AtlasCat(102, bbbb, 2, 1, 0) }

可见已经遍历出列表中的各个元素,即:列表按数组解析,元素按json对象解析。

(3.2)前端 → 后端

 相对而言,前端传给后端的内容没有后端传给前端的那么复杂,因为QML端不会有自定义值类型(从(3.1.3)中代码可看出,在qml端,atlasCatList的类型是var,而不是也不能是QList<atlasCat>)。也就是说,前端传给后端的类型无非就是简单类型,枚举类型,对象和数组。即:
 在QML端不仅不识别接收AtlasCat类型,而且试图将json对象类型转为AtlasCat类型也不会被允许:

"Could not convert argument 0 at"
	 "onClicked@qrc:/xxxxx/main.qml:61"
"Passing incompatible arguments to C++ functions from JavaScript is dangerous and deprecated."
"This will throw a JavaScript TypeError in future releases of Qt!"

但是可以将json对象类型转为 QJsonObject 类型:

  1. QML端发起请求
Button {
   。。。
   text: qsTr("updateXxx")
   onClicked: {
      var obj = {};
         obj["uid"] = "uid444";
         obj["sn"] = "sn434323";
         obj["code"] = "code9988";
         obj["name"] = "张三";
         。。。
         bizObj1.updateXxx(obj);
   }
}
  1. 后端业务对象方法
    前端所调用的方法如下:
void BizObj::updateXxx(const QJsonObject &obj) {

    qDebug() << "BACKEND INVOKED ====";
    qDebug() << "BizObj::updateXxx() uid = " << m_uid;
    。。。
    qDebug() << endoscopy;
    qDebug() << "uid = " << obj.value("uid").toString();
    qDebug() << "sn= " << obj.value("sn").toString();
    qDebug() << "code= " << obj.value("code").toString();
    qDebug() << "name = " << obj.value("name").toString();

    emit updateXxxFinished("OK");
}

其中参数类型不能是自定义值类型,是QJsonObject。
代码输出为:

QJsonObject({"code":"code9988","sn":"sn434323","name":"张三","uid":"uid444"})
uid =  "uid444"
sn =  "sn434323"
coden =  "code9988"
name =  "张三"
(4)小结
  1. 有关QML APP开发中,前后端数据的传递,还请认真阅读官方文档 Data Type Conversion Between QML and C++
  2. 相比C++,QML所支持的类型较为简单,除了简单类型和枚举类型,就是json对象和json数组。
  3. 前端传给后端的JSON对象,不可以使用自定义类型转换(该部分有待进一步调研),可以考虑使用QJsonObject。

相关文档:

  1. QML APP开发套路(二):前/后端交互概述
  2. QML APP开发套路(一):概述
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值