QJSon自定义配置系统

    JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

    json和xml都可以构建配置文件,只是这两个各有优缺点。

    (1) 在可读性方面,JSON 和 XML 的数据可读性基本相同。JSON 和 XML 的可读性可谓不相上下,一边是建议的语法,一边是规范的标签形式,很难分出胜负。
    (2) 在可扩展性方面,XML 天生有很好的扩展性,JSON 当然也有,没有什么是 XML 能扩展,JSON 不能的。
    (3) 在编码难度方面,XML 有丰富的编码工具,比如 Dom4j、JDom 等,JSON 也有 json.org提供的工具,但是 JSON 的编码明显比 XML 容易许多,即使不借助工具也能写出 JSON的代码,可是要写好 XML 就不太容易了。
    (4) 在解码难度方面,XML 的解析得考虑子节点父节点,让人头昏眼花,而 JSON 的解析难
度几乎为0。这一点 XML 输的真是没话说。
    (5) 在流行度方面,XML 已经被业界广泛的使用,而 JSON 才刚刚开始,但是在 Ajax 这个特定的领域,未来的发展一定是 XML 让位于 JSON。到时 Ajax 应该变成 Ajaj(AsynchronousJavascript and JSON)了。
    (6) JSON 和 XML 同样拥有丰富的解析手段。
    (7) JSON 相对于 XML 来讲,数据的体积小。
    (8) JSON 与 JavaScript 的交互更加方便。
    (9) JSON 对数据的描述性比 XML 较差。
    (10) JSON 的速度要远远快于 XML。

    由于每个公司的产品需求不一样,可能会选择xml或者json,这并没有对错,只有适合不适合。

    从Qt5.15开始Qt安装就只能是自己静态编译和在线安装,你如果实在是想用离线安装包,那就得购买 Qt for Small Business 产品,这是一个新的Qt产品,面向小企业和初创企业,以低,低的价格。小型企业 Qt 许可证是用于嵌入式、桌面和移动软件开发的完整Qt许可证,每年只需 499 美元。

一、QJson

     QT4中使用第三方库QJson解析JSON文件。

    QT5新增加了处理JSON的类,类均以QJson开头,包含在QtCore模块中。QT5新增加六个相关类:

QJsonArray封装 JSON 数组
QJsonDocument读写JSON文档
QJsonObject封装 JSON 对象
QJsonValue封装 JSON 值
QJsonParseError报告 JSON 处理过程中出现的错误
QJsonObject::iterator用于遍历QJsonObject的STL风格的非const遍历器

    我现在使用使用的是QT6,再QT6中和QT5没有变化,一样的读写。

二、QJsonDocument

    QJsonDocument提供了读写Json文档的方法。

    QJsonDocument是一个包含了完整JSON文档的类,支持以UTF-8编码的文本和QT自身的二进制格式来读写JSON文档。

//从QVariant和QByteArray生成类
static QJsonDocument fromVariant(const QVariant &variant);
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error = nullptr);
QVariant             toVariant() const;
QByteArray           toJson(JsonFormat format = Indented) const;
​
bool isEmpty() const;//是否为空
bool isArray() const;//是否包含一个Array
bool isObject() const;//是否包含一个Object
  
QJsonObject object() const;//获取Object
QJsonArray  array() const;//获取Object数组
void        setObject(const QJsonObject &object);
void        setArray(const QJsonArray &array);
  
enum JsonFormat {
  Indented,//生成的字符串中用换行符分隔
  Compact  //不加换行符
};

 

三、QJsonArray

    QJsonArray封装了JSON数组。

    JSON数组是值的链表,可以插入和删除QJsonValue。

    QJsonArray与QVariantList可以相互转换。QJsonArray可以用size(), insert(), removeAt()进行操作,还可以用标准C++的迭代器模式来迭代其内容。

    QJsonArray是一个隐式共享的类,只要没有被改变,可以和创建QJsonArray的document共享数据。

通过QJsonDocument可以将一个QJsonArray转换成或转换自一个文本形式的JSON。

 

四、QJsonObject

    QJsonObject类用于封装JSON对象。JSON对象是包含键值对的链表,其中键是唯一的字符串,其值由QJsonValue代表。

    QJsonObject可以与QVariantMap相互转换,可以用size()来获得键值对的数目,insert()、remove()分别用来插入和删除pair。可以用标准C++的迭代器模式(iterator pattern)来迭代其内容。

    QJsonObject是一个隐式共享的类,只要没有被改变过,QJsonObject会和创建它的document共享数据。

可以通过QJsonDocument将QJsonObject和文本格式相互转换。

五、QJsonParesError

    QJsonParseError类用于在JSON解析中报告错误。

NoError:                 未发生错误
UnterminatedObject:      对象不正确地终止以右花括号结束
MissingNameSeparator:    分隔不同项的逗号丢失
UnterminatedArray:       数组不正确地终止以右中括号结束
MissingValueSeparator:   对象中分割 key/value 的冒号丢失
IllegalValue:            值是非法的
TerminationByNumber:     在解析数字时,输入流结束
IllegalNumber:           数字格式不正确
IllegalEscapeSequence:   在输入时,发生一个非法转义序列
IllegalUTF8String:       在输入时,发生一个非法 UTF8 序列
UnterminatedString:      字符串不是以引号结束
MissingObject:           一个对象是预期的,但是不能被发现
DeepNesting:             对解析器来说,JSON 文档嵌套太深
DocumentTooLarge:        对解析器来说,JSON 文档太大
GarbageAtEnd:            解析的文档在末尾处包含额外的乱码

 

六、QJsonValue

    QJsonValue类封装了JSON中的值。JSON中的值有6种基本类型:

    enum Type {
        Null =  0x0,
        Bool = 0x1,
        Double = 0x2,
        String = 0x3,
        Array = 0x4,
        Object = 0x5,
        Undefined = 0x80
    };

 

七、自定义Config数据类型

    这里的自定义的类型包括bool、int、float、double、string及其对应的数组,当然大家可以根据自己的需要定义其他类型,只要掌握道理就可以。

    类型如下:

typedef enum config_valuetype_e {
    VALUETYPE_Bool,
    VALUETYPE_BoolA,
    VALUETYPE_Int,
    VALUETYPE_IntA,
    VALUETYPE_Float,
    VALUETYPE_FloatA,
    VALUETYPE_Double,
    VALUETYPE_DoubleA,
    VALUETYPE_QString,
    VALUETYPE_QStringL,
}CONFIG_VALUETYPE_E;
typedef struct config_value_s{
    QString                ValueName;   //变量名
    int                    ValueNum;    //非数组值为1,数组则为数组长度
    CONFIG_VALUETYPE_E     ValueType;   //变量类型
    void                  *P_ValueData; //指向变量的地址
    config_value_s(QString na, CONFIG_VALUETYPE_E type, void *data, int num=1) {
        ValueName   = na;
        ValueNum    = num;
        ValueType   = type;
        P_ValueData = data;
    }
}CONFIG_VALUE_S;

 

八、实现Config类体

    主程序可以顺便往里面加入CONFIG_VALUE_S类型的变量,这样保证了灵活性,而且只用关系自己加了哪些变量,而不用关系变量的读写文件。

    如下是类的定义:

class JConfig
{
public:
    JConfig(QString file);
    ~JConfig();
​
    /*
     * Read Fun
     */
    bool Read_ConfigFile();
    bool ReadBool     (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool ReadBoolA    (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool ReadInt      (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool ReadIntA     (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool ReadFloat    (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool ReadFloatA   (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool ReadDouble   (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool ReadDoubleA  (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool ReadQString  (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool ReadQStringL (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
​
    /*
     * Wirte Fun
     */
    bool Wirte_ConfigFile();
    bool WirteBool     (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool WirteBoolA    (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool WirteInt      (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool WirteIntA     (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool WirteFloat    (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool WirteFloatA   (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool WirteDouble   (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool WirteDoubleA  (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool WirteQString  (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
    bool WirteQStringL (CONFIG_VALUE_S *value, QJsonObject &jsonobj);
​
    /*
     *
     */
    void AddValue(CONFIG_VALUE_S *value);
    void RemoveValue(CONFIG_VALUE_S *value);
    void SetValueNum(void *valuedata, int num);
​
private:
    QString                FileName;
    QList<CONFIG_VALUE_S*> Config_ValueList;//将所有变量保存在链表中
};

 

    如下是类的实现:

JConfig::JConfig(QString file)
{
    FileName = file;
}
​
JConfig::~JConfig()
{
​
}
​
/*
 * Read Fun
 */
bool JConfig::Read_ConfigFile()
{
    QFile loadFile(FileName.toStdString().c_str());
    if(!loadFile.open(QIODevice::ReadOnly)) {
        qDebug()<<FileName<<": could't open projects json";
        return false;
    }
​
    QByteArray allData = loadFile.readAll();
    loadFile.close();
​
​
    QJsonParseError json_error;
    QJsonDocument jsonDoc(QJsonDocument::fromJson(allData, &json_error));
    if(!jsonDoc.isNull() && json_error.error != QJsonParseError::NoError) {
        qDebug()<<FileName<<": json error!";
        return false;
    }
    QJsonObject tmpobj = jsonDoc.object();
​
    foreach (auto var, Config_ValueList) {
        switch (var->ValueType) {
        case (VALUETYPE_Bool) : {
            if (!ReadBool(var, tmpobj)) {
                qCritical()<<var->ValueName<<": read error";
            }
        }break;
        case (VALUETYPE_BoolA) : {
            if (!ReadBoolA(var, tmpobj)) {
                qCritical()<<var->ValueName<<": read error";
            }
        }break;
        case (VALUETYPE_Int) : {
            if (!ReadInt(var, tmpobj)) {
                qCritical()<<var->ValueName<<": read error";
            }
        }break;
        case (VALUETYPE_IntA) : {
            if (!ReadIntA(var, tmpobj)) {
                qCritical()<<var->ValueName<<": read error";
            }
        }break;
        case (VALUETYPE_Float) : {
            if (!ReadFloat(var, tmpobj)) {
                qCritical()<<var->ValueName<<": read error";
            }
        }break;
        case (VALUETYPE_FloatA) : {
            if (!ReadFloatA(var, tmpobj)) {
                qCritical()<<var->ValueName<<": read error";
            }
        }break;
        case (VALUETYPE_Double) : {
            if (!ReadDouble(var, tmpobj)) {
                qCritical()<<var->ValueName<<": read error";
            }
        }break;
        case (VALUETYPE_DoubleA) : {
            if (!ReadDoubleA(var, tmpobj)) {
                qCritical()<<var->ValueName<<": read error";
            }
        }break;
        case (VALUETYPE_QString) : {
            if (!ReadQString(var, tmpobj)) {
                qCritical()<<var->ValueName<<": read error";
            }
        }break;
        case (VALUETYPE_QStringL) : {
            if (!ReadQStringL(var, tmpobj)) {
                qCritical()<<var->ValueName<<": read error";
            }
        }break;
        default:break;
        }
    }
    return true;
}
​
bool JConfig::ReadBool(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr || !jsonobj.contains(value->ValueName)) return false;
​
    QJsonValue jvalue = jsonobj.value(value->ValueName);
    if (jvalue.isBool()) {
        (*(bool*)value->P_ValueData) = jvalue.toBool();
    }else{
        return false;
    }
    return true;
}
​
bool JConfig::ReadBoolA(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr || !jsonobj.contains(value->ValueName)) return false;
    QJsonValue jvalue = jsonobj.value(value->ValueName);
    if (jvalue.isArray()) {
        QJsonArray array = jvalue.toArray();
        bool *pData = (bool*)value->P_ValueData;
        for (int i = 0; ((i < array.size()) && (i < value->ValueNum)); ++i) {
            if (array.at(i).isBool()) {
                pData[i] = array.at(i).toBool();
            }else{
                return false;
            }
        }
    }else{
        return false;
    }
    return true;
}
​
bool JConfig::ReadInt(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr || !jsonobj.contains(value->ValueName)) return false;
​
    QJsonValue jvalue = jsonobj.value(value->ValueName);
    if (jvalue.isDouble()) {
        (*(int*)value->P_ValueData) = jvalue.toInt();
    }else{
        return false;
    }
    return true;
}
​
bool JConfig::ReadIntA(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr || !jsonobj.contains(value->ValueName)) return false;
    QJsonValue jvalue = jsonobj.value(value->ValueName);
    if (jvalue.isArray()) {
        QJsonArray array = jvalue.toArray();
        int *pData = (int*)value->P_ValueData;
        for (int i = 0; ((i < array.size()) && (i < value->ValueNum)); ++i) {
            if (array.at(i).isDouble()) {
                pData[i] = array.at(i).toInt();
            }else{
                return false;
            }
        }
    }else{
        return false;
    }
    return true;
}
​
bool JConfig::ReadFloat(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr || !jsonobj.contains(value->ValueName)) return false;
​
    QJsonValue jvalue = jsonobj.value(value->ValueName);
    if (jvalue.isDouble()) {
        (*(float*)value->P_ValueData) = jvalue.toDouble();
    }else{
        return false;
    }
    return true;
}
​
bool JConfig::ReadFloatA(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr || !jsonobj.contains(value->ValueName)) return false;
    QJsonValue jvalue = jsonobj.value(value->ValueName);
    if (jvalue.isArray()) {
        QJsonArray array = jvalue.toArray();
        float *pData = (float*)value->P_ValueData;
        for (int i = 0; ((i < array.size()) && (i < value->ValueNum)); ++i) {
            if (array.at(i).isDouble()) {
                pData[i] = array.at(i).toDouble();
            }else{
                return false;
            }
        }
    }else{
        return false;
    }
    return true;
}
​
bool JConfig::ReadDouble(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr || !jsonobj.contains(value->ValueName)) return false;
​
    QJsonValue jvalue = jsonobj.value(value->ValueName);
    if (jvalue.isDouble()) {
        (*(double*)value->P_ValueData) = jvalue.toDouble();
    }else{
        return false;
    }
    return true;
}
​
bool JConfig::ReadDoubleA(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr || !jsonobj.contains(value->ValueName)) return false;
    QJsonValue jvalue = jsonobj.value(value->ValueName);
    if (jvalue.isArray()) {
        QJsonArray array = jvalue.toArray();
        double *pData = (double*)value->P_ValueData;
        for (int i = 0; ((i < array.size()) && (i < value->ValueNum)); ++i) {
            if (array.at(i).isDouble()) {
                pData[i] = array.at(i).toDouble();
            }else{
                return false;
            }
        }
    }else{
        return false;
    }
    return true;
}
​
bool JConfig::ReadQString(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr || !jsonobj.contains(value->ValueName)) return false;
​
    QJsonValue jvalue = jsonobj.value(value->ValueName);
    if (jvalue.isString()) {
        (*(QString*)value->P_ValueData) = jvalue.toString();
    }else{
        return false;
    }
    return true;
}
​
bool JConfig::ReadQStringL(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr || !jsonobj.contains(value->ValueName)) return false;
    QJsonValue jvalue = jsonobj.value(value->ValueName);
    if (jvalue.isArray()) {
        QJsonArray array = jvalue.toArray();
        QStringList *pData = (QStringList*)value->P_ValueData;
        for (int i = 0; ((i < array.size()) && (i < value->ValueNum)); ++i) {
            if (array.at(i).isString()) {
                (*pData)[i] = array.at(i).toString();
            }else{
                return false;
            }
        }
    }else{
        return false;
    }
    return true;
}
​
/*
 * Wirte Fun
 */
bool JConfig::Wirte_ConfigFile()
{
    QJsonObject tmpobj;
    foreach (auto var, Config_ValueList) {
        switch (var->ValueType) {
        case (VALUETYPE_Bool) : {
            WirteBool(var, tmpobj);
        }break;
        case (VALUETYPE_BoolA) : {
            WirteBoolA(var, tmpobj);
        }break;
        case (VALUETYPE_Int) : {
            WirteInt(var, tmpobj);
        }break;
        case (VALUETYPE_IntA) : {
            WirteIntA(var, tmpobj);
        }break;
        case (VALUETYPE_Float) : {
            WirteFloat(var, tmpobj);
        }break;
        case (VALUETYPE_FloatA) : {
            WirteFloatA(var, tmpobj);
        }break;
        case (VALUETYPE_Double) : {
            WirteDouble(var, tmpobj);
        }break;
        case (VALUETYPE_DoubleA) : {
            WirteDoubleA(var, tmpobj);
        }break;
        case (VALUETYPE_QString) : {
            WirteQString(var, tmpobj);
        }break;
        case (VALUETYPE_QStringL) : {
            WirteQStringL(var, tmpobj);
        }break;
        default:break;
        }
    }
​
    //
    QJsonDocument document;
    document.setObject(tmpobj);
    QByteArray byte_array = document.toJson();
    FILE         *pfile;
    fopen_s(&pfile, FileName.toStdString().c_str(), "w+");
    fwrite(byte_array.data(), 1, byte_array.length(), pfile);
    fclose(pfile);
​
    return true;
}
​
bool JConfig::WirteBool(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr) return false;
    jsonobj.insert(value->ValueName, (*(bool*)value->P_ValueData));
    return true;
}
​
bool JConfig::WirteBoolA(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr) return false;
    bool *pData = (bool*)value->P_ValueData;
    QJsonArray jsonAr;
    for (int i = 0; i < value->ValueNum; ++i) {
        jsonAr.append(pData[i]);
    }
    jsonobj.insert(value->ValueName, QJsonValue(jsonAr));
    return true;
}
​
bool JConfig::WirteInt(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr) return false;
    jsonobj.insert(value->ValueName, (*(int*)value->P_ValueData));
    return true;
}
​
bool JConfig::WirteIntA(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr) return false;
    int *pData = (int*)value->P_ValueData;
    QJsonArray jsonAr;
    for (int i = 0; i < value->ValueNum; ++i) {
        jsonAr.append(pData[i]);
    }
    jsonobj.insert(value->ValueName, QJsonValue(jsonAr));
    return true;
}
​
bool JConfig::WirteFloat(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr) return false;
    jsonobj.insert(value->ValueName, (*(float*)value->P_ValueData));
    return true;
}
​
bool JConfig::WirteFloatA(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr) return false;
    float *pData = (float*)value->P_ValueData;
    QJsonArray jsonAr;
    for (int i = 0; i < value->ValueNum; ++i) {
        jsonAr.append(pData[i]);
    }
    jsonobj.insert(value->ValueName, QJsonValue(jsonAr));
    return true;
}
​
bool JConfig::WirteDouble(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr) return false;
    jsonobj.insert(value->ValueName, (*(double*)value->P_ValueData));
    return true;
}
​
bool JConfig::WirteDoubleA(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr) return false;
    double *pData = (double*)value->P_ValueData;
    QJsonArray jsonAr;
    for (int i = 0; i < value->ValueNum; ++i) {
        jsonAr.append(pData[i]);
    }
    jsonobj.insert(value->ValueName, QJsonValue(jsonAr));
    return true;
}
​
bool JConfig::WirteQString(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr) return false;
    jsonobj.insert(value->ValueName, (*(QString*)value->P_ValueData));
    return true;
}
​
bool JConfig::WirteQStringL(CONFIG_VALUE_S *value, QJsonObject &jsonobj)
{
    if (value == nullptr) return false;
    QStringList *pData = (QStringList*)value->P_ValueData;
    QJsonArray jsonAr;
    for (int i = 0; i < value->ValueNum; ++i) {
        jsonAr.append(pData->at(i));
    }
    jsonobj.insert(value->ValueName, QJsonValue(jsonAr));
    return true;
}
​
/*
 *
 */
void JConfig::AddValue(CONFIG_VALUE_S *value)
{
    if (value == nullptr) return;
    foreach (auto var, Config_ValueList) {
        if (var == value) return;
    }
    Config_ValueList.append(value);
}
​
void JConfig::RemoveValue(CONFIG_VALUE_S *value)
{
    if (value == nullptr) return;
    Config_ValueList.removeOne(value);
}
​
void JConfig::SetValueNum(void *valuedata, int num)
{
    if (valuedata == nullptr) return;
    foreach (auto var, Config_ValueList) {
        if (var->P_ValueData == valuedata) {
            var->ValueNum = num;
            return;
        }
    }
}


九、使用方法

    实现代码如下:

P_Config = new JKConfig("C:/test.config");//生成congfig类体
//添加config变量
P_Config->AddValue(new CONFIG_VALUE_S("valueb1", VALUETYPE_Bool,  &valueb1, 1));
P_Config->AddValue(new CONFIG_VALUE_S("valueb2", VALUETYPE_Bool,  &valueb2, 1));
P_Config->AddValue(new CONFIG_VALUE_S("valueb3", VALUETYPE_Bool,  &valueb3, 1));
P_Config->AddValue(new CONFIG_VALUE_S("valueb4", VALUETYPE_Bool,  &valueb4, 1));
P_Config->AddValue(new CONFIG_VALUE_S("valueba1", VALUETYPE_BoolA, &valueba1, 10));
P_Config->AddValue(new CONFIG_VALUE_S("valueia1", VALUETYPE_IntA, &valueia1, 10));
P_Config->AddValue(new CONFIG_VALUE_S("valueda1", VALUETYPE_DoubleA, &valueda1, 10));
P_Config->Read_ConfigFile();//读
P_Config->Wirte_ConfigFile();//写

输出:

{
    "valueb1": false,
    "valueb2": true,
    "valueb3": false,
    "valueb4": false,
    "valueba1": [
        false,
        false,
        false,
        false,
        false,
        false,
        false,
        false,
        false,
        false
    ],
    "valueda1": [
        0,
        1.236,
        2.472,
        3.708,
        4.944,
        6.18,
        7.416,
        8.652,
        9.888,
        11.124
    ],
    "valueia1": [
        0,
        1,
        2,
        3,
        4,
        5,
        6,
        7,
        8,
        9
    ]
}

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值