Trying to learn Web Services with Qt (using Qt Creator 4.1.0) and connecting data to the GUI. I have read several online examples (most notably: 1, 2 and 3) but my low coding level along with the fact that I could not find full examples that were demonstrating my needs lead me here :).
I have created a simple example so that contains all my shortcomings:
json data format - example:
{
"city": "London",
"time": "16:42",
"unit_data":
[
{
"unit_data_id": "ABC123",
"unit_data_number": "21"
}
]
}
My simple Qt GUI design (made in Qt Creator) displaying all the fetched parsed data:
I would really appreciate any full code example that show how we can make a request to a web service and then how to fetch the json response. Finally, how to connect the GUI in Qt to display this data as soon as they are received.
I am just starting studying this area and I am in need of a simple full code example to get me going.
Here is a fully working example on how to send a GET request with parameters to a web service using QNetworkAccessManager
and parse the JSON response using QJsonDocument
.
In the example, I am sending a request to http://uinames.com/
whose responses are encoded in JSON in the following format:
{
"name":"John",
"surname":"Doe",
"gender":"male",
"region":"United States"
}
I am parsing the JSON response and displaying it in a 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();
}
Since you asked about how to use a QTimer
to trigger the update every one minute, replace the connect
call of the button clicked
signal from the code above with something like this:
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
As noted in comments, if you are using this in your window class's constructor, you have to make sure that the networkManager
, networkRequest
, the GUI components, and the timer
here are kept alive as long as your window object is running. So, you may choose to allocate them in the heap or as class members.