一.ui界面的设计流程

1.窗口1:使用水平布局,内包含俩个QLabel类和一个QLineEdit类

这里可以设置LineEdit中的提示文字 

2.窗口2:使用栅格布局,这个天气图标组件的大小需限制一下

 3.窗口3:里面包含一个子窗口,设置子窗口背景样式为橘色

子窗口中的组件先垂直布局,后水平布局。最后整体再来一个栅格布局

4.窗口4:里面包含6个子窗口。子窗口0401、0402、0406都需要进行栅格布局

子窗口0401和0406中的组件是由俩个QLabel类拼接在一起的。

 

5.最后给4个窗口整体进行垂直布局即可

二.功能实现逻辑

2.1 如何实现单击右键时,弹出菜单,供用户选择是否要退出的功能?

解决方法:重写鼠标点击事件,以及绑定信号与槽。 当用户单击右键时候,在点击位置处显示出该菜单。当用户选择菜单后,会发出triggered信号,调用槽函数即可。

构造函数中先初始化菜单类

myMenu = new QMenu(this);                                         //创建一个菜单加"Quit"和"not Quit"动作
QAction *QuitAction = new QAction("Quit", myMenu);
QAction *notQuitAction = new QAction("Not Quit", myMenu);
myMenu->addAction(QuitAction);                                    //往菜单中添加组件 
myMenu->addAction(notQuitAction);

connect(myMenu, &QMenu::triggered, this, [=](QAction *action){    //当用户点击这些动作时,会发出triggered信号
    if (action->text() == "Quit") {
        this->close();
    } else if (action->text() == "Not Quit") {
        return;
    }
});

重写鼠标点击事件

void Widget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::RightButton){                               //当检测到鼠标右键按下时,在当前点击位置弹出菜单
        myMenu->exec(QCursor::pos());
    }
    QWidget::mousePressEvent(event);
}

2.2 如何实现用户鼠标左键拖拽窗口移动功能?

解决方法:重写鼠标点击事件和鼠标移动事件。

void Widget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::RightButton){                               //当检测到鼠标右键按下时,在当前点击位置弹出菜单
        myMenu->exec(QCursor::pos());
    }
    if(event->button() == Qt::LeftButton){
        mOffset = event->globalPos() - this->pos();                       //偏移值等于鼠标当前位置减去窗口当前的位置
    }
    QWidget::mousePressEvent(event);
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    //鼠标当前位置减去偏移值等于新的窗口的左顶点坐标
    this->move(event->globalPos() - mOffset);
}

2.3 如何获取天气数据?

解决方法:QT调用HTTP请求相应的网站会返回 JSON 数据,解析该JSON数据中包含了天气数据

步骤1:首先打开下面网站,进行用户注册,随后会生成id和密码(后续http请求的网址中要包含的)

实时天气预报api 24小时天气预报接口 实时气象预警 空气质量预报

 或者通过别的api进行访问天气情况,使用时候需更换后面的city_id的值即可

http://t.weather.itboy.net/api/weather/city/101030100

步骤2:网站主页有相应的网址访问示例,如果想访问特定城市,需在链接后面拼接城市id等数据

步骤3:复制所有json内容,通过以下网站可以解析这些数据,选择你所需要字段名

JSON在线解析及格式化验证 - JSON.cn

步骤四:除此之外,你还需要有存储着城市姓名和城市id的文档,以便于你后期搜索城市天气时候,可以根据该文档获取到城市的city_id,然后拼接网址进行HTTP请求

通过以下代码可以实现查询城市id时,不用每次都重新打开json文档,而是把json文档中的city_name和 city_id键值对存入QMap中,当需要时直接在QMap中进行查找并返回相应的city_id

#include <QFile>
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include "citycodeutils.h"

CityCodeUtils::CityCodeUtils() {}

// 根据用户输入的城市名在QMap中检索,返回相应的code_id
QString CityCodeUtils::getCityCodeFromName(QString cityName)
{
    // 如果QMap为空,则调用初始化函数,解析json数据提取城市名字和id存入QMap中
    if(cityMap.isEmpty()){
        initCityMap();
    }
    QString city_name2 = QString("%1市").arg(cityName); //假设用户输入的不带市
    QString city_name3 = QString("%1县").arg(cityName); //假设用户输入的不带县
    QString city_name4 = cityName;                      //假设用户输入的带市,但是我们不需要市
    if (city_name4.contains("市")) {
        city_name4.remove("市");
    }
    QString city_name5 = cityName;                      //假设用户输入的带县,但是我们不需要县
    if (city_name5.contains("县")) {
        city_name5.remove("县");
    }

    QMap<QString, QString>::const_iterator it = cityMap.constBegin();  //迭代器指向QMap的起始
    while (it != cityMap.constEnd()) {                                 //利用迭代器遍历QMap
        if(it.key() == cityName || it.key() == city_name2 || it.key() == city_name3 || it.key() == city_name4 ||it.key() == city_name5){
            return it.value();                                         //返回对应的code_id
            break;                                                     //返回后结束当前循环
        }
        ++it;
    }
    return 000000;                                                     //若没有找到匹配的,则返000000,代表错误代码
}

// 负责解析本地的json数据,提取出城市名字和code_id存入QMap中
void CityCodeUtils::initCityMap()
{
    QFile file(":/aaa.json");
    file.open(QIODevice::ReadOnly);
    QString data = QString::fromUtf8(file.readAll());
    file.close();
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data.toUtf8());    //将读取的json字符串转化为jsonDocument文档

    // 准备一个 QMap 来存储解析的数据
    QMap<QString, QString> dataMap;
    // 如果jsonDocument文档是一个数组
    if (!jsonDoc.isNull() && jsonDoc.isArray()) {
        QJsonArray jsonArray = jsonDoc.array();                        //将json文档转化为一个jsonArray数组
        for (const QJsonValue &value : jsonArray) {                    //遍历数组中的每个对象
            if (value.isObject()) {
                QJsonObject jsonObj = value.toObject();                //将数组中的对象赋值给json对象,然后根据键值对提取json对象中的内容
                QString city_name = jsonObj["city_name"].toString();
                QString city_code = jsonObj["city_code"].toString();
                cityMap.insert(city_name,city_code);                   //向QMap中插入键值对
            }
        }
    }
}

2.4 如何实现将网站返回的json天气数据缓存下来

解决方法:先检查是否有本地缓存的json天气数据,如果有的话,则进一步判断该文件是否过期,如果没过期的话,就解析旧的json天气数据。否则进行http请求,将返回的json天气数据保存下来,然后进行解析该数据,往控件上显示。否则,旧进行http请求。

并且当用户搜索相应的城市天气时,我先不进行http请求,我检查一下这个新的网址和旧的网址是不是一样的,如果是一样的,那就重复上述步骤,查看本地是否有缓存的json天气数据,以及该数据是否过期。如果文件不存在或已过期,或者是网址与旧的网址不同,那么就进行http请求。

/*解析json数据*/
void Widget::praseJsonData(QString jsonString) {
    // 将JSON字符串转换为QJsonDocument文档
    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8());

    // 检查JSON文档是否有效
    if (jsonDoc.isNull() || !jsonDoc.isObject()) {
        qDebug() << "Invalid JSON data!";
        return;
    }
    // 把JSON文档转化为json对象
    QJsonObject jsonObj = jsonDoc.object();

    // 城市信息解析(**城市名称,省会名称**)
    if (jsonObj.contains("cityInfo") && jsonObj["cityInfo"].isObject()) {
        QJsonObject cityInfo = jsonObj["cityInfo"].toObject();
        QString city = cityInfo.value("city").toString("未知城市");
        QString parent = cityInfo.value("parent").toString("未知省份");
        QString updateTime = cityInfo.value("updateTime").toString("未知时间");
        ui->label_city->setText(QString("%1, %2").arg(parent).arg(city)); // *设置城市名称和省份
    }


    // 天气数据解析
    if (jsonObj.contains("data") && jsonObj["data"].isObject()) {
        QJsonObject data = jsonObj["data"].toObject();

        ui->label_WeatherNum->setText(data.value("wendu").toString("N/A") + "℃");      // *设置当天温度
        ui->label_WetNum->setText(data.value("shidu").toString("N/A"));                 // *设置当天湿度
        ui->label_AirNum->setText(data.value("quality").toString("N/A"));               // *设置当天空气质量
        qint16 Pm25 = data.value("pm25").toInt(-1);                                     // 获取当天的pm2.5
        ui->label_PmNum->setText(QString::number(Pm25));                                // *设置当天PM2.5
        ui->label_GanMao->setText(data.value("ganmao").toString("N/A"));                // *设置提示信息

        // 解析昨天的天气
        if (data.contains("yesterday") && data["yesterday"].isObject()) {
            QJsonObject yestObj = data["yesterday"].toObject();
            QString high = extractTemperature(yestObj.value("high").toString());        // 获取并提取昨天的最高温度
            dayHighTem[0] = high;
            QString low = extractTemperature(yestObj.value("low").toString());          // 获取并提取昨天的最低温度
            dayLowTem[0] = low;
            QString type = yestObj.value("type").toString("未知");                       // 获取昨天的天气状况
            QString date = yestObj.value("ymd").toString("未知日期");                     // 获取昨天的日期
            qint16 aqi = yestObj.value("aqi").toInt(-1);                                 // 获取昨天的空气质量指数
            ui->label_01->setStyleSheet(aqi <= 50 ? "background-color: rgb(85, 170, 0);" :
                                                        (aqi <= 100 ? "background-color: rgb(255, 146, 21);" :
                                                                      "background-color: rgb(255, 0, 0);"));

            QStringList parts = date.split("-");
            QString lastDate = parts.size() == 3 ? QString("%1-%2").arg(parts[1]).arg(parts[2]) : "未知日期";
            ui->label_date1->setText(lastDate);                                          // *设置昨天的日期
            ui->label_sweather01->setText(type);                                         // *设置昨天的天气

            auto it = mTypeMap.find(type);                                               // *设置昨天的天气图片
            if (it != mTypeMap.end()) {
                QString IconPath = it.value();
                QPixmap pixmap(IconPath);
                ui->label_sweather1->setPixmap(pixmap);
            } else {
                qDebug() << "Weather type not found in mTypeMap:" << type;
            }

            ui->label_01->setText(aqi <= 50 ? "优" : (aqi <= 100 ? "良" : "差"));          // *设置昨天的空气质量
            ui->label_windDir1->setText(yestObj.value("fx").toString("未知风向"));         // *设置昨天的风向
            ui->label_windDir01->setText(yestObj.value("fl").toString("未知风级"));        // *设置昨天的风级
        }

        // 解析未来天气预报
        if (data.contains("forecast") && data["forecast"].isArray()) {
            QJsonArray forecastArray = data["forecast"].toArray();
            int i = 1;
            for (const QJsonValue &value : forecastArray) {
                if (value.isObject()) {
                    QJsonObject forecast = value.toObject();
                    QString high = extractTemperature(forecast.value("high").toString());   //获取并提取出最高温度
                    dayHighTem[i] = high;
                    QString low = extractTemperature(forecast.value("low").toString());     //获取并提取出最低温度
                    dayLowTem[i] = low;
                    QString type = forecast.value("type").toString("未知");                  //获取天气情况
                    QString date = forecast.value("ymd").toString("未知日期");               //获取日期
                    QString fx = forecast.value("fx").toString("未知风向");                  //获取风向
                    QString fl = forecast.value("fl").toString("未知风级");                  //获取风级
                    qint16 aqi = forecast.value("aqi").toInt(-1);                          //获取空气指数

                    QStringList parts = date.split("-");
                    QString lastDate = parts.size() == 3 ? QString("%1-%2").arg(parts[1]).arg(parts[2]) : "未知日期";

                    if(i == 1){
                        ui->label_WeatherStaute->setText(type);                            //设置当天的天气情况
                        ui->label_FxTitle->setText(fx);                                    //设置当天的风向
                        ui->label_FxNum->setText(fl);                                      //设置当天的风级
                    }

                    QLabel *label_day = findChild<QLabel *>(QString("label_day%1").arg(i + 1));
                    QLabel *label_date = findChild<QLabel *>(QString("label_date%1").arg(i + 1));
                    QLabel *label_sweather = findChild<QLabel *>(QString("label_sweather0%1").arg(i + 1));
                    QLabel *label_windDir = findChild<QLabel *>(QString("label_windDir%1").arg(i + 1));
                    QLabel *label_windDir0 = findChild<QLabel *>(QString("label_windDir0%1").arg(i + 1));
                    QLabel *label_airQuality = findChild<QLabel *>(QString("label_0%1").arg(i + 1));

                    if (label_day && label_date && label_sweather && label_windDir && label_windDir0 && label_airQuality) {
                        label_day->setText(i == 1 ? "今天" : forecast.value("week").toString("未知"));     //*设置星期几
                        label_date->setText(lastDate);                                                    //*设置日期
                        label_sweather->setText(type);                                                    //*设置天气情况
                        label_windDir->setText(fx);                                                       //*设置风向
                        label_windDir0->setText(fl);                                                      //*设置风级

                        QString airStatus = (aqi <= 50) ? "优" : ((aqi <= 100) ? "良" : "差");
                        label_airQuality->setText(airStatus);                                             //*设置空气质量
                        label_airQuality->setStyleSheet(aqi <= 50 ? "background-color: rgb(85, 170, 0);" :
                                                                    (aqi <= 100 ? "background-color: rgb(255, 146, 21);" :
                                                                                  "background-color: rgb(255, 0, 0);"));
                        auto it = mTypeMap.find(type);
                        if (it != mTypeMap.end()) {
                            QString IconPath = it.value();
                            QPixmap pixmap(IconPath);
                            if(i == 1){                                                                   //*设置当天的天气质量图片
                                ui->label_WeatherImage->setPixmap(pixmap);
                            }
                            QLabel *label_weatherIcon = findChild<QLabel *>(QString("label_sweather%1").arg(i + 1));
                            if (label_weatherIcon) {
                                label_weatherIcon->setPixmap(pixmap);                                    //*设置天气质量图片
                            }
                        }
                    } else {
                        qDebug() << "One or more labels not found for day" << i;
                    }
                    if(i < 5){
                        i++;
                    }

                }
            }

        }
    }
    update(); // 更新界面

}

//获取http请求的数据并将返回数据保存到本地文档中
void Widget::readHttpRequest()
{
    int resCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();    // 获取返回码,正确获取为200,错误时为404
    qDebug() << "resCode:" << resCode;
    if(resCode == 200 && reply->error() == QNetworkReply::NoError){
        QString response = QString::fromUtf8(reply->readAll());                           //获取返回信息
        QFile file("C:/Users/mi/Desktop/Qt_Project/Weather-forecast/json_data");
        if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)){
            qDebug() << "文件打开失败";
        }
        file.write(response.toLocal8Bit());                                               //将返回的json数据写入文件中
        file.close();
        praseJsonData(response);                                                          //解析json数据
    }else{
        qDebug() << "Error:" << reply->errorString();                                     //获取错误信息
        QMessageBox::warning(this,"错误","网络请求失败",QMessageBox::Ok);
    }
}

//检查本地json文件是否存在,以及是否该重新访问
void Widget::checkAndLoadWeatherData()
{
    QString cacheFilePath = "C:/Users/mi/Desktop/Qt_Project/Weather-forecast/json_data"; // 缓存文件路径
    QFileInfo cacheFileInfo(cacheFilePath);

    if (cacheFileInfo.exists()) {
        // 文件存在,检查是否过期
        QDateTime lastModified = cacheFileInfo.lastModified();
        QDateTime currentTime = QDateTime::currentDateTime();

        qint64 elapsedSecs = lastModified.secsTo(currentTime);
        qDebug() << "缓存存在,距离上次修改的时间:" << elapsedSecs << "秒";

        if (elapsedSecs <= 3600) { // 如果文件修改时间在1小时内
            // 解析本地缓存文件
            QFile cacheFile(cacheFilePath);
            if (cacheFile.open(QIODevice::ReadOnly)) {
                QString jsonData = QString::fromLocal8Bit(cacheFile.readAll());
                cacheFile.close();
                qDebug() << "使用本地缓存数据";
                praseJsonData(jsonData);
                return; // 使用缓存数据后返回
            }
        }
    }

    // 如果缓存不存在或已过期,则发送 HTTP 请求
    qDebug() << "缓存无效,发送HTTP请求获取数据";
    QUrl url(website);
    QNetworkRequest request(url);
    reply = manager->get(request);
}

//根据用户输入的城市名进行查询天气数据
void Widget::weatherSearch()
{
    QString ser_city_name = ui->lineEdit_searchData->text();                               //获取用户输入的城市名
    QString cityCode = citycodeUtils->getCityCodeFromName(ser_city_name);                  //获取返回的城市id
    if(cityCode == 000000){                                                                //返回错误代码,则不进行http请求
        QMessageBox msgBox;
        msgBox.setText("未检索到城市.");
        msgBox.exec();
    }else{
        website = QString("http://t.weather.itboy.net/api/weather/city/%1").arg(cityCode); //拼接要访问的网址
        if(website == lastwebsite){                                                        //如果此次访问的和上次访问的一样,则不进行http请求
            checkAndLoadWeatherData();
        }else{
            lastwebsite = website;
            QUrl url(website);
            QNetworkRequest request(url);
            reply = manager->get(request);                                                 //进行http请求
        }
    }
}

2.5 如何在控件上绘制6天的高低温折线图?

解决方法:重写事件过滤函数,为控件widget_0404和widget_0405安装事件过滤器

检测到绘制信号时候,调用函数进行绘制高低温曲线

/*绘制低温曲线*/
void Widget::drawTempLineHigh()
{
    QPainter painter(ui->widget_0404);
    painter.setRenderHint(QPainter::Antialiasing, true);              //启用抗锯齿

    int sum = 0;
    int ave;
    int offset = 0;
    int middle = ui->widget_0404->height() / 2;

    QFont font("Arial", 10);
    painter.setFont(font);

    for (int i = 0; i < 6; i++) {
        sum += dayHighTem[i].toInt();
    }
    ave = sum / 6;

    QPoint points[6];
    for (int i = 0; i < 6; i++) {
        points[i].setX(lab[i]->x() + lab[i]->width() / 2);             //当前点的横坐标位置与其头顶上方的空气质量组件有关
        offset = dayHighTem[i].toInt() - ave;                          //偏移值等于当天温度-平均值,可乘以适当倍数以增加曲率
        points[i].setY(middle - offset);                               //因为画笔直接与当前窗口关联了,所以纵坐标等于当前窗口高度-偏移值
        painter.setPen(Qt::yellow);
        painter.setBrush(Qt::yellow);

        painter.drawEllipse(points[i], 2, 2);                          //绘制圆点

        QString temperatureText = QString("%1℃").arg(dayHighTem[i]);
        QPoint textPosition(points[i].x() - 7, points[i].y() + 15);    //调整文字位置
        painter.setPen(QColor(Qt::white));
        painter.drawText(textPosition, temperatureText);               //在点的下方绘制温度值
    }

    painter.setPen(Qt::yellow);
    for (int i = 0; i < 5; i++) {
        painter.drawLine(points[i], points[i + 1]);                    //绘制5条温度西线
    }
}

/*绘制高温曲线*/
void Widget::drawTempLineLow()
{
    QPainter painter(ui->widget_0405);
    painter.setRenderHint(QPainter::Antialiasing, true);

    int sum = 0;
    int ave;
    int offset = 0;
    int middle = ui->widget_0405->height() / 2;

    QFont font("Arial", 10);
    painter.setFont(font);

    for (int i = 0; i < 6; i++) {
        sum += dayLowTem[i].toInt();
    }
    ave = sum / 6;

    QPoint points[6];
    for (int i = 0; i < 6; i++) {
        points[i].setX(lab[i]->x() + lab[i]->width() / 2);
        offset = dayLowTem[i].toInt() - ave;
        points[i].setY(middle - offset);

        painter.setPen(QColor(35, 255, 255));
        painter.setBrush(QColor(35, 255, 255));
        painter.drawEllipse(points[i], 2, 2);

        QString temperatureText = QString("%1℃").arg(dayLowTem[i]);
        QPoint textPosition(points[i].x() - 7, points[i].y() + 15);
        painter.setPen(QColor(Qt::white));
        painter.drawText(textPosition, temperatureText);
    }

    painter.setPen(QColor(35, 255, 255));
    for (int i = 0; i < 5; i++) {
        painter.drawLine(points[i], points[i + 1]);
    }
}

/*事件过滤函数*/
bool Widget::eventFilter(QObject *watched, QEvent *event)
{
    if(watched == ui->widget_0404 && event->type() == QEvent::Paint){
        drawTempLineHigh();
        return true;
    }
    if(watched == ui->widget_0405 && event->type() == QEvent::Paint){
        drawTempLineLow();
        return true;
    }
    return QWidget::eventFilter(watched,event);
}

三.HTTP通信知识补充

3.1 QT实现HTTP通信

HTTP(超文本传输协议)是用于分布式、协作式和超媒体信息系统的应用层协议,是万维网(WWW)的数据通信的基础。了解HTTP的基本概念对于理解现代网络通信至关重要。以下是HTTP的一些核心概念:

请求和响应: HTTP是一个基于请求-响应模式的协议。客户端(通常是Web浏览器)向服务器发送一个HTTP请求,然后服务器返回一个HTTP响应。请求包含请求的资源(如网页),而响应包含请求的资源的内容。
HTTP方法:
  • HTTP定义了一系列的方法来表明对资源的不同操作,最常用的包括:
    • GET:用于请求资源。
    • POST:用于提交数据给服务器(例如,表单数据)。
    • PUT:用于上传文件或内容。
    • DELETE:用于请求删除资源。
    • HEAD:用于获取资源的元信息,而不是资源本身。
状态码:
  • 服务器对请求的响应中包含一个状态码,它表示请求的成功或失败,以及失败的原因。常见的状态码包括:
    • 200 OK:请求成功。
    • 404 Not Found:请求的资源未找到。
    • 500 Internal Server Error:服务器内部错误。

Qt中的HTTP编程涉及到使用Qt中的网络模块来进行HTTP请求和处理HTTP响应。

QNetworkAccessManager,QNetworkRequest,QNetworkReply

以下程序展示了如何使用Qt发送一个简单的HTTP请求并处理响应

//包含在头文件中
QNetworkAccessManager *manager;
QNetworkReply *reply;


//包含在构造函数中
manager = new QNetworkAccessManager(this);
QNetworkRequest request(QUrl("http://t.weather.itboy.net/api/weather/city/101010100"));
reply = manager->get(request);
connect(reply, &QNetworkReply::finished, this, &Widget::readHttpRequest);
//或者绑定完成信号与manager对象更好
//connect(manager,&QNetworkAccessManager::finished, this, &Widget::readHttpRequest);

//自定义函数
void Widget::readHttpRequest()
{
    int resCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // 获取返回码,正确获取为200,错误时为404
    qDebug() << "resCode:" << resCode;
    if(resCode == 200 && reply->error() == QNetworkReply::NoError){
        QString response = QString::fromUtf8(reply->readAll());                           //获取返回信息
        qDebug() << "response:" << response;
    }else{
        qDebug() << "Error:" << reply->errorString();                                 //获取错误信息
        QMessageBox::warning(this,"错误","网络请求失败",QMessageBox::Ok);
    }
}

3.2 Qt生成JSON数据

JSON(JavaScript ObjectNotation)是一种轻量级的数据交换格式。它易于人阅读和编写,同时也易于机器解析和生成。JSON是基于JavaScript的一个子集,尽管它是独立于语言的,且有多种语言支持。JSON常用于网络应用程序中的数据传输,尤其是在Web应用程序中与后端服务器通信。

在Qt中生成JSON数据并将其保存到文件的一个基本示例涉及使用QJsonDocument、QJsonObject和QJsonArray类。以下是创建一个简单JSON对象并将其保存到文件的示例代码。

#include <QJsonDocument>
#include <QJsonObject>
#include <QFile>
#include <QDebug>
#include <QJsonArray>


QJsonObject rootObj;                  //创建一个json对象,键值对
rootObj["cityid"] = "1010100";
rootObj["date"] = "2024-11-13";
rootObj["weather"] = "雨夹雪";

QJsonArray jsonArr;                   //创建一个JSON数组
jsonArr.append("C++");
jsonArr.append("Python");             
rootObj["languages"]=jsonArr;         //将数组添加到JSON对象

QJsonDocument JsonDoc(rootObj);       //将json对象转化为json文档
QByteArray json = JsonDoc.toJson();   //将json文档转化为字符串

QFile file("C:/Users/mi/Desktop/Qt_Project/Qt_JsonData/jsonData");
if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)){
    qDebug() << "文件打开失败";
}
file.write(json);                     //写入文件中
file.close();

3.3 Qt解析JSON数据

在Qt中解析JSON数据通常涉及到使用QJsonDocument、QJsonObject和QJsonArray类。这些类提供了处理JSON数据的必要工具,使您能够从JSON字符串中提取信息、遍历JSON对象或数组,并访问具体的数据项。

以下是如何在Qt中解析这个JSON字符串的步骤:

示例1:json文档中只包含1个对象

// 1.使用了原始字符串字面量来定义JSON字符串,这样可以避免转义特殊字符
QString jsonString = R"(
                     {
                     "name": "John Doe",
                     "age": 30,
                     "email": "john.doe@example.com",
                     "skills": ["C++", "Python", "JavaScript"]
                     }
                     )";

// 2.将JSON字符串转换为QJsonDocument文档
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8());

// 3.检查JSON文档是否包含一个对象
if (!jsonDoc.isNull() && jsonDoc.isObject()) {
    // 3.1获取JSON对象并访问其键值
    QJsonObject jsonObj = jsonDoc.object();
    
    QString name = jsonObj["name"].toString();
    int age = jsonObj["age"].toInt();
    QString email = jsonObj["email"].toString();
    
    qDebug() << "Name:" << name;
    qDebug() << "Age:" << age;
    qDebug() << "Email:" << email;
    
    // 3.2获取JSON对象中的数组
    if (jsonObj.contains("skills") && jsonObj["skills"].isArray()) {
        QJsonArray skillsArray = jsonObj["skills"].toArray();
        for (const QJsonValue &value : skillsArray) {
            qDebug() << "Skill:" << value.toString();
        }
    }
} else {
    qDebug() << "Invalid JSON.";
}

示例2:json文档中包含多个对象

// 1.定义一个包含多个对象的JSON字符串
QString jsonString = R"(
                     [
                     {
                     "name": "小李",
                     "age": 18,
                     "email": "xiaoli.doe@example.com",
                     "skills": ["C++", "Python", "JavaScript"]
                     },
                     {
                     "name": "小美",
                     "age": 25,
                     "email": "xiaomei.smith@example.com",
                     "skills": ["Java", "C#", "PHP"]
                     }
                     ]
                     )";

// 2.将JSON字符串转换为QJsonDocument对象
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8());

// 3.检查JSON文档是否包含一个数组,多个对象保存到一个数组中
if (!jsonDoc.isNull() && jsonDoc.isArray()) {
    QJsonArray jsonArray = jsonDoc.array();                     //3.1获取json文档中的数组
    for (const QJsonValue &value : jsonArray) {                 //3.2遍历数组中的每个对象
        if (value.isObject()) {
            QJsonObject jsonObj = value.toObject();             //3.3将数组中的对象赋值给json对象,然后根据键值对提取json对象中的内容
            QString name = jsonObj["name"].toString();
            int age = jsonObj["age"].toInt();
            QString email = jsonObj["email"].toString();
            qDebug() << "Name:" << name;
            qDebug() << "Age:" << age;
            qDebug() << "Email:" << email;
            
            if (jsonObj.contains("skills") && jsonObj["skills"].isArray()) {
                QJsonArray skillsArray = jsonObj["skills"].toArray();
                for (const QJsonValue &skillValue : skillsArray) {
                    qDebug() << "Skill:" << skillValue.toString();
                }
            }
        }
    }
} else {
    qDebug() << "Invalid JSON or not an array.";
}

3.4 Qt解析JSON数据并存储到QMap类中

// JSON 字符串
QString jsonString = R"(
                     {
                     "name": "John Doe",
                     "age": "30",
                     "email": "john.doe@example.com"
                     }
                     )";

// 将 JSON 字符串转换为 QJsonDocument
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8());

// 准备一个 QMap 来存储解析的数据
QMap<QString, QString> dataMap;

// 解析 JSON 对象并填充 QMap
if (!jsonDoc.isNull() && jsonDoc.isObject()) {
    QJsonObject jsonObj = jsonDoc.object();
    for (auto key : jsonObj.keys()) {
        dataMap[key] = jsonObj.value(key).toString();
    }
} else {
    qDebug() << "Invalid JSON...";
}

// 打印 QMap 内容
for (auto key : dataMap.keys()) {
    qDebug() << key << ": " << dataMap[key];
}

四.整体代码实现如下

tunnek/mimi: QT——天气预报项目 (github.com)

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐