向 Web 服务发出获取请求,获取 json 响应并在 Qt 中更新 GUI

Posted

技术标签:

【中文标题】向 Web 服务发出获取请求,获取 json 响应并在 Qt 中更新 GUI【英文标题】:Make get request to web service, get json response and update GUI in Qt 【发布时间】:2016-09-15 19:18:01 【问题描述】:

尝试使用 Qt(使用 Qt Creator 4.1.0)学习 Web 服务将数据连接到 GUI。我已经阅读了几个在线示例(最值得注意的是:1、2 和 3),但我的编码水平较低,而且我找不到能证明我的需求的完整示例,这导致我来到这里 :)。

我创建了一个简单的例子来包含我所有的缺点:

每 30 秒向(现有)网络服务发出 HTTP 获取请求。 Web 服务随后通过发送一个 json 数据对象(请参阅下面的此类 json 示例格式)来响应我们接收和解析。 然后,Qt 会将所有已解析的 json 数据显示到一个简单的 GUI 上(请参阅下面的 GUI 外观。

json数据格式——示例


    "city": "London",
    "time": "16:42",
    "unit_data": 
        [
            
                "unit_data_id": "ABC123",
                "unit_data_number": "21"
            
        ]

我的简单 Qt GUI 设计(在 Qt Creator 中制作) 显示所有获取的解析数据:

我非常感谢任何完整的代码示例,这些示例展示了我们如何向 Web 服务发出请求,然后如何获取 json 响应。最后,如何在 Qt 中连接 GUI 以在收到数据后立即显示。

我刚开始研究这个领域,我需要一个简单的完整代码示例来帮助我学习。

【问题讨论】:

您是否编写了代码来每 30 秒向(现有)Web 服务发出 HTTP 获取请求?您显示了 JSON 格式和 GUI,但没有显示您尝试过的任何代码。 @Mike 我找到了QNetworkAccessManager 的一些示例,但是我的入门级缺少任何完整的教程和示例导致一无所获。所以,我没有实际的代码,只有几次失败的代码块尝试。上述问题的任何指南和代码都将帮助我深入研究该主题。 【参考方案1】:

这是一个完整的示例,说明如何使用 QNetworkAccessManager 将带有参数的 GET 请求发送到 Web 服务,并使用 QJsonDocument 解析 JSON 响应。

在示例中,我正在向http://uinames.com/ 发送一个请求,其响应以 JSON 格式编码,格式如下:


    "name":"John",
    "surname":"Doe",
    "gender":"male",
    "region":"United States"

我正在解析 JSON 响应并将其显示在 GUI 中。

#include <QtWidgets>
#include <QtNetwork>

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    //setup GUI (you could be doing this in the designer)
    QWidget widget;
    QFormLayout layout(&widget);
    QLineEdit lineEditName;
    QLineEdit lineEditGender;
    QLineEdit lineEditRegion;
    auto edits = &lineEditName, &lineEditGender, &lineEditRegion;
    for(auto edit : edits) edit->setReadOnly(true);
    layout.addRow("Name:", &lineEditName);
    layout.addRow("Gender:", &lineEditGender);
    layout.addRow("Region:", &lineEditRegion);
    QPushButton button("Get Name");
    layout.addRow(&button);

    //send request to uinames API
    QNetworkAccessManager networkManager;
    QObject::connect(&networkManager, &QNetworkAccessManager::finished,
                     [&](QNetworkReply* reply)
        //this lambda is called when the reply is received
        //it can be a slot in your GUI window class
        //check for errors
        if(reply->error() != QNetworkReply::NoError)
            for(auto edit : edits) edit->setText("Error");
            networkManager.clearAccessCache();
         else 
            //parse the reply JSON and display result in the UI
            QJsonObject jsonObject= QJsonDocument::fromJson(reply->readAll()).object();
            QString fullName= jsonObject["name"].toString();
            fullName.append(" ");
            fullName.append(jsonObject["surname"].toString());
            lineEditName.setText(fullName);
            lineEditGender.setText(jsonObject["gender"].toString());
            lineEditRegion.setText(jsonObject["region"].toString());
        
        button.setEnabled(true);
        reply->deleteLater();
    );
    //url parameters
    QUrlQuery query;
    query.addQueryItem("amount", "1");
    query.addQueryItem("region", "United States");
    QUrl url("http://uinames.com/api/");
    url.setQuery(query);
    QNetworkRequest networkRequest(url);
    //send GET request when the button is clicked
    QObject::connect(&button, &QPushButton::clicked, [&]()
        networkManager.get(networkRequest);
        button.setEnabled(false);
        for(auto edit : edits) edit->setText("Loading. . .");
    );

    widget.show();
    return a.exec();

编辑:

由于您询问如何使用QTimer 来触发每分钟更新一次,请将上面代码中对按钮clicked 信号的connect 调用替换为以下代码:

QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [&]()
    networkManager.get(networkRequest);
    button.setEnabled(false);
    for(auto edit : edits) edit->setText("Loading. . .");
);
timer.start(60000); //60000 msecs = 60 secs

如 cmets 中所述,如果您在窗口类的构造函数中使用它,则必须确保 networkManagernetworkRequest、GUI 组件和此处的 timer 保持活动状态,只要您的窗口对象正在运行。因此,您可以选择将它们分配在堆中或作为类成员。

【讨论】:

这很完美,即使不是我的例子,它也清楚地表明了我想要理解的内容。谢谢。小问题,如果我有一个QMainWindow 类,这是否意味着你的所有代码都进入了该类的构造函数? 在与QMainWindow 的第一个问题相同的主题上,我尝试在课堂上复制您的代码(经过一些修改),但出现很多错误;也许您会简要解释一下它应该如何工作?谢谢 @nk-fford ,我无法访问您的网络服务,这就是为什么我按照您的要求编写了一个通用示例,该示例确实可以正常工作。不,您不会将所有代码原样复制到QMainWindow 的构造函数中。主要问题是networkManagernetworkRequest 和所有 GUI 组件都需要保持活动状态,只要您的 QMainWindow 正在运行。您可以选择将它们分配在堆上或作为类成员。此外,您可能希望将 lambda 函数替换为插槽。 如果您使用 GUI 设计器,默认情况下 GUI 组件是动态分配的,您可以使用 ui 指针访问它们。此处的示例演示了QNetworkAccessManagerQJsonDocument 的用法。将其放入 QMainWindow 时遇到的问题属于通用 C++ 语言。我在 main 函数中编写所有代码的原因是为了让示例尽可能地最小化和可验证。 @nk-fford ,我已经更新了答案。尽管我认为这应该作为separate question 询问QTimer,因为这与使用QNetworkAccessManager 和从Qt 访问Web 服务没有密切关系。

以上是关于向 Web 服务发出获取请求,获取 json 响应并在 Qt 中更新 GUI的主要内容,如果未能解决你的问题,请参考以下文章

从排序中的响应中获取标题

响应正文为空(获取请求)[重复]

请求失败时从 AlamoFire 获取 JSON 响应

如何从get请求获取json响应而不是html响应?

从 SOAP 响应中获取 JSON

http 的8中请求方式: