如何使用异步源获取自定义小部件的数据
How to get data for a custom widget using an async source
我是 QT 的新手,我需要一些帮助。如果你们中有人能帮助我,我将不胜感激。
问题:
我有一个异步 class 发出 HTTP 请求,它将接收一些数据并转换成 JSON 格式,然后我将从那里提取应该传递给我的自定义的必要信息小部件。我怎样才能做到这一点?因为不知道信息什么时候到。
到目前为止我做了什么:
我的 HTTP 请求和解析 JSON class:
WeatherAPI::WeatherAPI(QObject *parent) : QObject(parent) {
manager = new QNetworkAccessManager(this);
QObject::connect(manager, SIGNAL(finished(QNetworkReply * )), this, SLOT(readData(QNetworkReply * )));
}
void WeatherAPI::readData(QNetworkReply *reply) {
if (reply->error() == QNetworkReply::NoError) {
QString strReply = (QString) reply->readAll();
QJsonDocument jsonResponse = QJsonDocument::fromJson(strReply.toUtf8());
QJsonObject jsonObject = jsonResponse.object();
weatherObject.city = jsonObject["name"].toString();
weatherObject.temperature = QString::number(jsonObject["main"].toObject()["temp"].toDouble() - 273.15);
int ts = jsonObject["dt"].toInt();
weatherObject.time = QDateTime::fromSecsSinceEpoch(ts).toString("hh:mm");
auto weatherData = jsonObject["weather"].toArray()[0].toObject()["main"].toString();
if (weatherData == "Clouds") {
weatherObject.icon = "Sun.png";
}
} else {
qDebug() << "ERROR";
}
}
void WeatherAPI::requestDataForCity(const QString &city) {
QString link = linkTemplate.arg(city, key);
QUrl url(link);
manager->get(QNetworkRequest(url));
}
const WeatherObject &WeatherAPI::getWeatherObject() const {
return weatherObject;
}
现在这是我的自定义小部件:
void WeatherButton::initStyle(const QJsonValue &json) {
PolygonButtonWidget::initStyle(json);
auto cities = json.toObject()["cities"].toArray();
api = new WeatherAPI(this);
for (auto c: cities) {
QString city = c.toString();
api->requestDataForCity(city); // HERE I'm making the http request
WeatherObject data = api->getWeatherObject();//HERE I'm getting the DATA
m_title = data.city;
m_time = data.time;
m_icon = data.icon;
m_temperature = data.temperature;
}
}
在 WeatherButton::initStyle 的函数中,我将发出 HTTP 请求,并将数据放入必要的变量中。现在我的问题是......我如何才能等待接收到数据,然后再将它们放入这些变量中?
到目前为止,我所知道的唯一解决方案是使用 QEventLoop,但那时我基本上要将异步调用转换为同步调用,这不是我想要的。我想完全异步。
WeatherObject data = api->getWeatherObject(); //HERE I'm getting the DATA
不,您不会在此处获取数据。 WeatherAPI::readData
是您获取数据的地方。
那就是Signal - Slot mechanism的重点了。您无需等待事件发生,而是通过回调(即插槽)对其做出反应。
考虑到这一点,您必须重新考虑并扩展您的代码。这是一种方法:
在WeatherAPI
class定义一个dataReady(const WeatherObject &weatherObject)
信号
在 WeatherAPI::readData
中发出此信号,如下所示:
void WeatherAPI::readData(QNetworkReply *reply) {
if (reply->error() == QNetworkReply::NoError) {
// the processing of the http response remains unchanged
// ...
emit dataReady(weatherObject);
} else {
qDebug() << "ERROR";
}
}
在 WeatherButton
class 中定义一个具有以下实现的 onDataReady
插槽:
void WeatherButton::onDataReady(const WeatherObject &weatherObject) {
m_title = weatherObject.city;
m_time = weatherObject.time;
m_icon = weatherObject.icon;
m_temperature = weatherObject.temperature;
}
像这样连接 WeatherButton::initStyle
中新创建的信号和槽:
void WeatherButton::initStyle(const QJsonValue &json) {
PolygonButtonWidget::initStyle(json);
auto cities = json.toObject()["cities"].toArray();
api = new WeatherAPI(this);
connect(api, &WeatherAPI::dataReady, this, &WeatherButton::onDataReady);
for (auto c: cities) {
QString city = c.toString();
api->requestDataForCity(city); // HERE I'm making the http request
}
}
作为旁注我应该说,initStyle
可能不是实例化 WeatherAPI
的最佳位置。 api
似乎是 WeatherButton
的一个属性,因此它应该在 class.
的构造函数中初始化
我是 QT 的新手,我需要一些帮助。如果你们中有人能帮助我,我将不胜感激。
问题:
我有一个异步 class 发出 HTTP 请求,它将接收一些数据并转换成 JSON 格式,然后我将从那里提取应该传递给我的自定义的必要信息小部件。我怎样才能做到这一点?因为不知道信息什么时候到。
到目前为止我做了什么:
我的 HTTP 请求和解析 JSON class:
WeatherAPI::WeatherAPI(QObject *parent) : QObject(parent) {
manager = new QNetworkAccessManager(this);
QObject::connect(manager, SIGNAL(finished(QNetworkReply * )), this, SLOT(readData(QNetworkReply * )));
}
void WeatherAPI::readData(QNetworkReply *reply) {
if (reply->error() == QNetworkReply::NoError) {
QString strReply = (QString) reply->readAll();
QJsonDocument jsonResponse = QJsonDocument::fromJson(strReply.toUtf8());
QJsonObject jsonObject = jsonResponse.object();
weatherObject.city = jsonObject["name"].toString();
weatherObject.temperature = QString::number(jsonObject["main"].toObject()["temp"].toDouble() - 273.15);
int ts = jsonObject["dt"].toInt();
weatherObject.time = QDateTime::fromSecsSinceEpoch(ts).toString("hh:mm");
auto weatherData = jsonObject["weather"].toArray()[0].toObject()["main"].toString();
if (weatherData == "Clouds") {
weatherObject.icon = "Sun.png";
}
} else {
qDebug() << "ERROR";
}
}
void WeatherAPI::requestDataForCity(const QString &city) {
QString link = linkTemplate.arg(city, key);
QUrl url(link);
manager->get(QNetworkRequest(url));
}
const WeatherObject &WeatherAPI::getWeatherObject() const {
return weatherObject;
}
现在这是我的自定义小部件:
void WeatherButton::initStyle(const QJsonValue &json) {
PolygonButtonWidget::initStyle(json);
auto cities = json.toObject()["cities"].toArray();
api = new WeatherAPI(this);
for (auto c: cities) {
QString city = c.toString();
api->requestDataForCity(city); // HERE I'm making the http request
WeatherObject data = api->getWeatherObject();//HERE I'm getting the DATA
m_title = data.city;
m_time = data.time;
m_icon = data.icon;
m_temperature = data.temperature;
}
}
在 WeatherButton::initStyle 的函数中,我将发出 HTTP 请求,并将数据放入必要的变量中。现在我的问题是......我如何才能等待接收到数据,然后再将它们放入这些变量中?
到目前为止,我所知道的唯一解决方案是使用 QEventLoop,但那时我基本上要将异步调用转换为同步调用,这不是我想要的。我想完全异步。
WeatherObject data = api->getWeatherObject(); //HERE I'm getting the DATA
不,您不会在此处获取数据。 WeatherAPI::readData
是您获取数据的地方。
那就是Signal - Slot mechanism的重点了。您无需等待事件发生,而是通过回调(即插槽)对其做出反应。
考虑到这一点,您必须重新考虑并扩展您的代码。这是一种方法:
在
WeatherAPI
class定义一个dataReady(const WeatherObject &weatherObject)
信号在
WeatherAPI::readData
中发出此信号,如下所示:void WeatherAPI::readData(QNetworkReply *reply) { if (reply->error() == QNetworkReply::NoError) { // the processing of the http response remains unchanged // ... emit dataReady(weatherObject); } else { qDebug() << "ERROR"; } }
在
WeatherButton
class 中定义一个具有以下实现的onDataReady
插槽:void WeatherButton::onDataReady(const WeatherObject &weatherObject) { m_title = weatherObject.city; m_time = weatherObject.time; m_icon = weatherObject.icon; m_temperature = weatherObject.temperature; }
像这样连接
WeatherButton::initStyle
中新创建的信号和槽:void WeatherButton::initStyle(const QJsonValue &json) { PolygonButtonWidget::initStyle(json); auto cities = json.toObject()["cities"].toArray(); api = new WeatherAPI(this); connect(api, &WeatherAPI::dataReady, this, &WeatherButton::onDataReady); for (auto c: cities) { QString city = c.toString(); api->requestDataForCity(city); // HERE I'm making the http request } }
作为旁注我应该说,initStyle
可能不是实例化 WeatherAPI
的最佳位置。 api
似乎是 WeatherButton
的一个属性,因此它应该在 class.