Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Qt - CPP - How to get data for a custom widget using an async source
Forum Updated to NodeBB v4.3 + New Features

Qt - CPP - How to get data for a custom widget using an async source

Scheduled Pinned Locked Moved Unsolved General and Desktop
3 Posts 3 Posters 273 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • V Offline
    V Offline
    Vildnex
    wrote on last edited by
    #1

    I'm new to QT and I would like some help. If any of you could help me I would really appreciate it.

    QUESTION:

    I have an asynchronous class that makes an HTTP request and it's going to receive some data into a JSON format and from there I will extract the necessary information which should be passed to my custom widget. How can I do that? Because I don't know when the information will arrive.

    WHAT I'VE DONE SO FAR:

    My HTTP request and parsing 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;
    }
    

    Now here is my custom Widget:

    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;
        }
    }
    

    In that function from WeatherButton::initStyle I'm going to make an HTTP request and also I'm going to place the data into the necessary variable. Now my question is... How can I wait for that data to be received and just after that to place them into those variables?

    So far the only solution I know so far is to use a QEventLoop, but at that moment I'm going to basically convert an async call into a sync one, which is not quite what I want. I want to be fully async.

    JonBJ 1 Reply Last reply
    0
    • V Vildnex

      I'm new to QT and I would like some help. If any of you could help me I would really appreciate it.

      QUESTION:

      I have an asynchronous class that makes an HTTP request and it's going to receive some data into a JSON format and from there I will extract the necessary information which should be passed to my custom widget. How can I do that? Because I don't know when the information will arrive.

      WHAT I'VE DONE SO FAR:

      My HTTP request and parsing 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;
      }
      

      Now here is my custom Widget:

      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;
          }
      }
      

      In that function from WeatherButton::initStyle I'm going to make an HTTP request and also I'm going to place the data into the necessary variable. Now my question is... How can I wait for that data to be received and just after that to place them into those variables?

      So far the only solution I know so far is to use a QEventLoop, but at that moment I'm going to basically convert an async call into a sync one, which is not quite what I want. I want to be fully async.

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @Vildnex said in Qt - CPP - How to get data for a custom widget using an async source:

      but at that moment I'm going to basically convert an async call into a sync one, which is not quite what I want. I want to be fully async.

      What do you mean by "fully async"? :) initStyle() is called synchronously from code, so yes it requires a blocking call here. Or, you have to figure a way to maybe redraw your custom weather widget as & when the asynchronous data arrives, which is presumably the best you can hope to achieve?

      As a separate issue/on top of that, perhaps you should consider caching the HTTP data for future use, e.g. in this method?

      1 Reply Last reply
      0
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #3

        Hi,

        From your WeatherAPI, you should emit a signal that will propagate the data received and connect that signal to whatever slot you need to update your widget.

        Out of curiosity, why are you using the old syntax with a lambda when you could directly connect the slot ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        1

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved