最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

QT實(shí)現(xiàn)C++數(shù)據(jù)類與json轉(zhuǎn)換

 更新時(shí)間:2025年04月23日 08:36:45   作者:永不停轉(zhuǎn)  
這篇文章主要為大家詳細(xì)介紹了如何使用QT實(shí)現(xiàn)C++數(shù)據(jù)類與json轉(zhuǎn)換,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

QT 提供了 QJsonDocument、QJsonObject、QJsonArray、QJsonValue 等類用于 JSON 的解析和轉(zhuǎn)換。QJsonValue 支持的數(shù)據(jù)類型包括:bool、double、string、array、object、null。但是,對(duì)于 QRectF、QLineF、QColor 等類以及用戶自定義數(shù)據(jù)類,QJsonObject 就無(wú)法轉(zhuǎn)換,更無(wú)法生成可讀的字符串。此時(shí),需要我們自己來(lái)實(shí)現(xiàn)轉(zhuǎn)換并定義轉(zhuǎn)換后的 JSON 格式。

上篇文章,借助 QT 的反射機(jī)制實(shí)現(xiàn)數(shù)據(jù)類的序列化 實(shí)現(xiàn)了數(shù)據(jù)類的序列化,簡(jiǎn)化了數(shù)據(jù)類的編寫(xiě),同時(shí)提供了轉(zhuǎn)換為 JSON 的基礎(chǔ)。通過(guò)元對(duì)象系統(tǒng)很容易找到我們通過(guò)宏 JSONFIELD 記錄的需要序列化的字段,因?yàn)橛涗浶蛄谢姆椒ū粚?dǎo)出并標(biāo)記為 JSON_FLAG 。使用反射機(jī)制就可以找到所有記錄序列化字段的方法,獲取字段名后通過(guò) getValue()、setValue() 即可獲取或設(shè)置字段值。

// serializable.h
#define JSONFIELD(field, alias, ...) \
using __type_##field = decltype(field) ;\
Q_PROPERTY(__type_##field field READ get##alias WRITE set##alias) \
    public: \
    Q_INVOKABLE JSON_FLAG inline QMap<QString, QString> __get##alias##Info__(){ \
        QMap<QString, QString> info; \
        info["name"] = #field; \
        info["alias"] = #alias; \
        info["args"] = QString(#__VA_ARGS__); \
        return info; \
    } \
    inline __type_##field get##alias() const { return field; } \
    inline void set##alias(const __type_##field &value) { \
            field = value; \
    }

定義通用的 JSON 接口

JSON 接口主要定義 4 個(gè)功能接口:1. 將數(shù)據(jù)類轉(zhuǎn)換為 QJsonObject 對(duì)象;2. 將數(shù)據(jù)類轉(zhuǎn)換為字符串;3. 將字符串解析為指定的數(shù)據(jù)類;4. 將 QJsonObject 轉(zhuǎn)換為指定的數(shù)據(jù)類;

系統(tǒng)允許多個(gè)接口實(shí)現(xiàn)類,但是全局只允許有一個(gè)實(shí)例,用于整個(gè)工程的 JSON 轉(zhuǎn)換。所以聲明了一個(gè)全局的 EasyJson 對(duì)象 EASYJSON。

#include "serializable.h"

#include <QJsonObject>

class EasyJson{
public:
    EasyJson(){}
    ~EasyJson(){}
    virtual QJsonObject toJson(const Serializable &obj) = 0;
    virtual QString toJsonString(const Serializable &obj) = 0;
    virtual QVariant parseObject(QJsonObject json, QMetaType typeName) = 0;
    virtual QVariant parseObject(QString json, QMetaType typeName) = 0;
};

extern EasyJson *EASYJSON;

EasyJson 的實(shí)現(xiàn)類

實(shí)現(xiàn)類直接繼承 EasyJson 類,完成接口代碼即可。QT 中數(shù)據(jù)類轉(zhuǎn)換為 JSON 的難點(diǎn)在于 QRectF、QSizeF 等類的轉(zhuǎn)換,以及 Serializable 作為數(shù)據(jù)類字段時(shí)的轉(zhuǎn)換。為了便于 QT 內(nèi)部封裝類的解析,需要將解析方法單獨(dú)封裝為一個(gè)工具類,這樣便于后期添加和修改。工具類的實(shí)現(xiàn)見(jiàn) variantutil.h 文件。

// easyjsonimpl.h
#include "easyjson.h"

class EasyJsonImpl: public EasyJson
{
public:
    EasyJsonImpl();

    // EasyJson interface
private:
    QJsonObject toJson(const Serializable &obj) override;
    QString toJsonString(const Serializable &obj) override;
    QVariant parseObject(QJsonObject json, QMetaType typeName) override;
    QVariant parseObject(QString json, QMetaType typeName) override;
};

為了便于切換不同的 JSON 實(shí)現(xiàn)類,EASYJSON 對(duì)象的創(chuàng)建與否需要通過(guò)指定的宏來(lái)判斷一下。如 EasyJsonImpl 源碼中規(guī)定只有定義了 EASY_JSON_DEFAULT 才會(huì)實(shí)例化 EasyJsonImpl。

這樣在 .pro 文件中添加 DEFINES += EASY_JSON_DEFAULT 即可啟用該實(shí)現(xiàn)類。如果有不同的實(shí)現(xiàn)類,定義不同的宏即可。

// easyjsonimpl.cpp
#include "easyjsonimpl.h"
#include "variantutil.h"

#include <QObject>
#include <QMetaObject>
#include <QMetaProperty>
#include <QColor>
#include <QJsonArray>
#include <QLineF>
#include <QPointF>
#include <QRectF>
#include <QSizeF>
#include <QJsonDocument>

#ifdef EASY_JSON_DEFAULT
EasyJson *EASYJSON = new EasyJsonImpl();
#endif

EasyJsonImpl::EasyJsonImpl() {}

QJsonObject EasyJsonImpl::toJson(const Serializable &obj)
{
    QJsonObject json;
    Serializable *objPtr = const_cast<Serializable*>(&obj);

    const QMetaObject *metaInfo = obj.getMetaInfo();//obj.metaObject();
    do{
        int count = metaInfo->methodCount();
        for(int i=0; i< count; i++){
            if (QString(metaInfo->method(i).tag()).compare("JSON_FLAG") == 0){
                QMap<QString, QString> jsonInfo;
                jsonInfo = objPtr->invokeMethod<QMap<QString, QString>>(metaInfo, i);
                QString alias = jsonInfo["alias"];
                QVariant value = objPtr->getValue(jsonInfo["name"]);
                QMetaType type = value.metaType();
                // 對(duì) Serializable 子類遞歸轉(zhuǎn)換
                if (type.id() > QMetaType::User) {
                    auto valueMeta = type.metaObject();
                    auto classInfo = valueMeta->classInfo(valueMeta->indexOfClassInfo("base"));
                    if (QString("Serializable").compare(classInfo.value()) == 0) {
                        json.insert(alias, toJson(*reinterpret_cast<const Serializable*>(value.constData())));
                        continue;
                    }
                }
                // 轉(zhuǎn)為json對(duì)象
                json.insert(alias, VariantUtil::toJsonValue(value));
            }
        }

        metaInfo = metaInfo->superClass();
    }while(metaInfo != nullptr);
    return json;
}

QString EasyJsonImpl::toJsonString(const Serializable &obj)
{
    QJsonObject json = toJson(obj);
    QJsonDocument doc(json);
    return QString(doc.toJson(QJsonDocument::Compact));
}

QVariant EasyJsonImpl::parseObject(QJsonObject json, QMetaType typeName)
{
    const QMetaObject *metaInfo = typeName.metaObject();
    QVariant result(typeName);
    Serializable *obj = reinterpret_cast<Serializable*>(result.data());
    do{
        int count = metaInfo->methodCount();
        for(int i=0; i< count; i++){
            if (QString(metaInfo->method(i).tag()).compare("JSON_FLAG") == 0){
                QMap<QString, QString> jsonInfo = obj->invokeMethod<QMap<QString, QString>>(metaInfo, i);

                QMetaProperty fieldType = metaInfo->property(metaInfo->indexOfProperty(jsonInfo["name"].toLocal8Bit()));
                QByteArray fieldName = jsonInfo["name"].toLocal8Bit();
                if (!json.contains(jsonInfo["alias"])){
                    continue;
                }
                QJsonValueRef jsonValue = json[jsonInfo["alias"]];
                // 對(duì) Serializable 子類遞歸解析
                if (fieldType.metaType().id() > QMetaType::User) {
                    auto valueMeta = fieldType.metaType().metaObject();
                    auto classInfo = valueMeta->classInfo(valueMeta->indexOfClassInfo("base"));
                    if (QString("Serializable").compare(classInfo.value()) == 0) {
                        obj->setValue(fieldName,
                                         parseObject(jsonValue.toObject(), fieldType.metaType()));
                        continue;
                    }
                }
                // 設(shè)置字段值
                obj->setValue(fieldName,
                              VariantUtil::fromJsonValue(jsonValue, fieldType.metaType()));
            }
        }
        metaInfo = metaInfo->superClass();
    }while(metaInfo != nullptr);
    return result;
}

QVariant EasyJsonImpl::parseObject(QString json, QMetaType typeName)
{
    if (json.isEmpty()) {
        return QVariant(typeName);
    }
    QJsonDocument doc = QJsonDocument::fromJson(json.toLocal8Bit());
    return parseObject(doc.object(), typeName);
}

variantutil 部分源碼如下,詳細(xì)代碼請(qǐng)到項(xiàng)目 https://github.com/lsyeei/dashboard 的源碼目錄 /common/ 中查看 variantutil.h 文件。

inline QJsonValue VariantUtil::toJsonValue(const QVariant &var)
{
    auto type = var.metaType();
    switch (type.id()) {
    case QMetaType::QPoint:
        return QJsonArray{var.toPoint().x(), var.toPoint().y()};
        break;
    case QMetaType::QPointF:
        return QJsonArray{var.toPointF().x(), var.toPointF().y()};
        break;
	...
	default:
        if (type.flags().testFlag(QMetaType::IsEnumeration)) {
            return var.toInt();
        } else {
            return QJsonValue::fromVariant(var);
        }
        break;
    }
}

inline QVariant VariantUtil::fromJsonValue(const QJsonValue &val, QMetaType type)
{
    switch (type.id()) {
    case QMetaType::QPoint:
        return [=]{
            QJsonArray array(val.toArray());
            QPoint pt(array[0].toInt(), array[1].toInt());
            return QVariant(pt);}();
        break;
    case QMetaType::QPointF:
        return [=]{
            QJsonArray array(val.toArray());
            QPointF pt(array[0].toDouble(), array[1].toDouble());
            return QVariant(pt);}();
        break;
	...
	default:
        return val.toVariant();
        break;
    }
}

使用 EASYJSON

首先 .pro 文件中添加 DEFINES += EASY_JSON_DEFAULT 啟用該實(shí)現(xiàn)類。需要序列化的數(shù)據(jù)類繼承 Serializable 類,然后調(diào)用對(duì)應(yīng)的方法即可EASYJSON->toJsonString(pen)。

項(xiàng)目 Compelling Data Designer 用于數(shù)據(jù)的可視化設(shè)計(jì),軟件采用可擴(kuò)展架構(gòu),支持?jǐn)U展圖形插件、數(shù)據(jù)接口。項(xiàng)目仍在開(kāi)發(fā)中,目前已設(shè)計(jì)完成基本圖形、多屬性配置、動(dòng)畫(huà)等功能。項(xiàng)目中還提供了 JSON 序列化數(shù)據(jù)類的實(shí)現(xiàn)方式。

到此這篇關(guān)于QT實(shí)現(xiàn)C++數(shù)據(jù)類與json轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)QT C++數(shù)據(jù)類轉(zhuǎn)json內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談C結(jié)構(gòu)和C++結(jié)構(gòu)之間的區(qū)別

    淺談C結(jié)構(gòu)和C++結(jié)構(gòu)之間的區(qū)別

    這篇文章主要介紹了淺談C結(jié)構(gòu)和C++結(jié)構(gòu)之間的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Matlab處理圖像后實(shí)現(xiàn)簡(jiǎn)單的人臉檢測(cè)

    Matlab處理圖像后實(shí)現(xiàn)簡(jiǎn)單的人臉檢測(cè)

    本文主要介紹一下如何使用matlab進(jìn)行圖像處理后實(shí)現(xiàn)人臉檢測(cè),感興趣的可以了解一下
    2021-11-11
  • 配置CLion管理Qt項(xiàng)目國(guó)際化支持的方法

    配置CLion管理Qt項(xiàng)目國(guó)際化支持的方法

    這篇文章主要介紹了配置CLion管理Qt項(xiàng)目國(guó)際化支持的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • C語(yǔ)言中關(guān)于scanf讀取緩存區(qū)的問(wèn)題

    C語(yǔ)言中關(guān)于scanf讀取緩存區(qū)的問(wèn)題

    scanf()函數(shù)是通用終端格式化輸入函數(shù),它從標(biāo)準(zhǔn)輸入設(shè)備(鍵盤(pán)) 讀取輸入的信息,接下來(lái)通過(guò)本文給大家介紹C語(yǔ)言中關(guān)于scanf讀取緩存區(qū)的問(wèn)題,需要的朋友一起看看吧
    2021-09-09
  • C++實(shí)現(xiàn)職工工資管理系統(tǒng)課程設(shè)計(jì)

    C++實(shí)現(xiàn)職工工資管理系統(tǒng)課程設(shè)計(jì)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)職工工資管理系統(tǒng)課程設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C語(yǔ)言中的for循環(huán)語(yǔ)句基本語(yǔ)法及使用

    C語(yǔ)言中的for循環(huán)語(yǔ)句基本語(yǔ)法及使用

    這篇文章主要介紹了C語(yǔ)言中的for循環(huán)語(yǔ)句基本語(yǔ)法及使用,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • C語(yǔ)言實(shí)現(xiàn)日期和時(shí)間處理的常用函數(shù)總結(jié)

    C語(yǔ)言實(shí)現(xiàn)日期和時(shí)間處理的常用函數(shù)總結(jié)

    在C語(yǔ)言中,時(shí)間和日期處理是一項(xiàng)非常基礎(chǔ)的技能,也是開(kāi)發(fā)實(shí)際應(yīng)用程序時(shí)經(jīng)常會(huì)用到的功能,本文為大家總結(jié)了C語(yǔ)言中一些常用的時(shí)間庫(kù)函數(shù),希望對(duì)大家有所幫助
    2023-06-06
  • 淺析bilateral filter雙邊濾波器的理解

    淺析bilateral filter雙邊濾波器的理解

    這篇文章主要介紹了bilateral filter雙邊濾波器的通俗理解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • C語(yǔ)言 指針數(shù)組詳解及示例代碼

    C語(yǔ)言 指針數(shù)組詳解及示例代碼

    本文主要介紹C語(yǔ)言 指針數(shù)組,這里提供詳細(xì)的資料和簡(jiǎn)單示例代碼以便大家學(xué)習(xí)參考,有需要學(xué)習(xí)的小伙伴可以參考下
    2016-08-08
  • C語(yǔ)言樸素模式匹配算法實(shí)例代碼

    C語(yǔ)言樸素模式匹配算法實(shí)例代碼

    樸素模式匹配算法也稱為布魯特-福斯算法,感覺(jué)很是高大上,但是實(shí)現(xiàn)起來(lái)很簡(jiǎn)單。這篇文章主要給大家介紹了關(guān)于C語(yǔ)言樸素模式匹配算法的相關(guān)資料,需要的朋友可以參考下
    2021-06-06

最新評(píng)論

玉门市| 志丹县| 武乡县| 榕江县| 安徽省| 隆德县| 论坛| 启东市| 新干县| 五莲县| 云梦县| 夏邑县| 三亚市| 红原县| 瑞丽市| 彭山县| 大埔区| 文山县| 温泉县| 个旧市| 兴山县| 南陵县| 无极县| 泽普县| 张家界市| 黄石市| 灌云县| 邯郸县| 英超| 古浪县| 始兴县| 饶河县| 吉隆县| 海口市| 康平县| 渭源县| 临泉县| 隆林| 冕宁县| 吴江市| 财经|