Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Update: Forum Guidelines & Code of Conduct

    Solved QNetworkReply destroyed before completing

    General and Desktop
    4
    8
    84
    Loading More Posts
    • 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.
    • L
      Laurentioos last edited by

      Hi guys,

      Quick disclaimer I've been at this for days and am probably overlooking something. I am also learning as I go so every chance I'm doing it very wrong. I've learned enough about QNetworkAccessManager etc to be dangerous but not competent :)

      The problem I have at the moment is that I need to run various get/post api calls to web services, which works fine if the code runs in a cli window but not a gui (QWidget) window. to narrow down the problem I created a test project with code snippets from tutorials:

      worker.h

      #ifndef WORKER_H
      #define WORKER_H
      
      #include <QObject>
      #include <QtDebug>
      #include <QNetworkAccessManager>
      #include <QNetworkReply>
      #include <QNetworkRequest>
      #include <QAuthenticator>
      #include <QNetworkProxy>
      
      class worker : public QObject
      {
          Q_OBJECT
      public:
          explicit worker(QObject *parent = nullptr);
      
      signals:
      
      public slots:
          void get(QString location);
          void post(QString location, QByteArray data);
      private slots:
              void readyRead();
              void authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator);
              void encrypted(QNetworkReply *reply);
              void finished(QNetworkReply *reply);
              void networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible);
              void preSharedKeyAuthenticationRequired(QNetworkReply *reply, QSslPreSharedKeyAuthenticator *authenticator);
              void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
              void sslErrors(QNetworkReply *reply, const QList<QSslError> &errors);
      
      private:
      
              QNetworkAccessManager manager;
      
      };
      
      #endif // WORKER_H
      
      
      

      worker.cpp

      #include "worker.h"
      
      worker::worker(QObject *parent) : QObject(parent)
      {
          connect(&manager,&QNetworkAccessManager::authenticationRequired,this,&worker::authenticationRequired);
          connect(&manager,&QNetworkAccessManager::encrypted,this,&worker::encrypted);
          connect(&manager,&QNetworkAccessManager::networkAccessibleChanged,this,&worker::networkAccessibleChanged);
          connect(&manager,&QNetworkAccessManager::preSharedKeyAuthenticationRequired,this,&worker::preSharedKeyAuthenticationRequired);
          connect(&manager,&QNetworkAccessManager::proxyAuthenticationRequired,this,&worker::proxyAuthenticationRequired);
          connect(&manager,&QNetworkAccessManager::sslErrors,this,&worker::sslErrors);
      }
      
      void worker::get(QString location)
      {
          qInfo() << "getting from server...";
          QNetworkReply* reply = manager.get(QNetworkRequest(QUrl(location)));
          connect(reply,&QNetworkReply::readyRead,this,&worker::readyRead);
      }
      
      void worker::post(QString location, QByteArray data)
      {
          qInfo() << "posting to server...";
          QNetworkRequest request = QNetworkRequest (QUrl(location));
          request.setHeader(QNetworkRequest::ContentTypeHeader,"text/plain");
          QNetworkReply* reply = manager.post(request,data);
          connect(reply,&QNetworkReply::readyRead,this,&worker::readyRead);
      }
      
      void worker::readyRead()
      {
          qInfo() << "ReadyRead";
          QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
          if(reply) qInfo () <<reply->readAll();
      }
      
      void worker::authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
      {
          Q_UNUSED(reply)
          Q_UNUSED(authenticator)
          qInfo() << "authenticationRequired";
      }
      
      void worker::encrypted(QNetworkReply *reply)
      {
          Q_UNUSED(reply)
          qInfo() << "encrypted";
      }
      
      void worker::finished(QNetworkReply *reply)
      {
          Q_UNUSED(reply)
          qInfo() << "finished";
      }
      
      void worker::networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible)
      {
          Q_UNUSED(accessible)
          qInfo() << "networkAccessibleChanged";
      }
      
      void worker::preSharedKeyAuthenticationRequired(QNetworkReply *reply, QSslPreSharedKeyAuthenticator *authenticator)
      {
          Q_UNUSED(reply)
          Q_UNUSED(authenticator)
          qInfo() << "preSharedKeyAuthenticationRequired";
      }
      
      void worker::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
      {
          Q_UNUSED(proxy)
          Q_UNUSED(authenticator)
          qInfo() << "proxyAuthenticationRequired";
      }
      
      void worker::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
      {
          Q_UNUSED(reply)
          Q_UNUSED(errors)
          qInfo() << "sslErrors";
      }
      
      

      mainwindow.h

      #ifndef MAINWINDOW_H
      #define MAINWINDOW_H
      
      #include <QMainWindow>
      
      namespace Ui {
      class MainWindow;
      }
      
      class MainWindow : public QMainWindow
      {
          Q_OBJECT
      
      public:
          explicit MainWindow(QWidget *parent = nullptr);
          ~MainWindow();
      
      private:
          Ui::MainWindow *ui;
      };
      
      #endif // MAINWINDOW_H
      
      

      mainwindow.cpp

      
      
      #include "mainwindow.h"
      #include "ui_mainwindow.h"
      #include "worker.h"
      
      MainWindow::MainWindow(QWidget *parent) :
          QMainWindow(parent),
          ui(new Ui::MainWindow)
      {
          ui->setupUi(this);
          worker Worker;
          QByteArray data;
          data.append("param1=hello");
          data.append("&");
          data.append("param2=world");
          Worker.post("https://postman-echo.com/post",data);
      }
      
      MainWindow::~MainWindow()
      {
          delete ui;
      }
      

      now I know the reply is being destroyed by adding the folowing code at the end of the post function

          connect(reply, &QObject::destroyed,
                  [] { qDebug() << "Sender got deleted!"; });
      

      for context the reason I'm attempting to call the functions within the mainwindow, is that there will be push buttons connected to functions that will download file, get a specific page etc.

      Thanks in advance!

      1 Reply Last reply Reply Quote 0
      • eyllanesc
        eyllanesc last edited by eyllanesc

        @Laurentioos move worker Worker; to

        // ...
        private:
            Ui::MainWindow *ui;
            worker Worker;
        };
        

        read about od scope in variables

        If you want me to help you develop some work then you can write to my email: e.yllanescucho@gmal.com.

        1 Reply Last reply Reply Quote 2
        • L
          Laurentioos last edited by

          @eyllanesc I dont understand why I would move the variable to mainwindow.h?

          quick bit of reading though and I guess I misunderstood the parent child relationship. I had thought that Worker would be a child of MainWindow, and exist so long as MainWindow exists, where am I right to understand it will only exist within the context of the function because I'm storing the class in a variable?

          eyllanesc 1 Reply Last reply Reply Quote 0
          • eyllanesc
            eyllanesc @Laurentioos last edited by eyllanesc

            @Laurentioos mmm, what you say about the relationship between QObjects is correct but creating a QObject inside a function that belongs to a class does not make the QObject a child of the class. In your case "Worker" is a local variable that will be destroyed as soon as the MainWindow constructor finishes executing. Please read https://doc.qt.io/qt-5/qobject.html#details.

            If you want it to be child then you must use a pointer and pass to this: worker *Worker = new worker(this);

            If you want me to help you develop some work then you can write to my email: e.yllanescucho@gmal.com.

            1 Reply Last reply Reply Quote 3
            • L
              Laurentioos last edited by

              Thanks @eyllanesc while I've not yet got this working in my main app I now understand why it wasn't. I think for the small size of this app I'll likely just declare the Worker variable outside the scope of any function within mainwindow.cpp

              I think I may also have some reading to do to properly understand your last suggestion re pointer and it's use case.

              1 Reply Last reply Reply Quote 0
              • SGaist
                SGaist Lifetime Qt Champion last edited by

                Hi

                @Laurentioos said in QNetworkReply destroyed before completing:

                I think for the small size of this app I'll likely just declare the Worker variable outside the scope of any function within mainwindow.cpp

                The size of the app does not matter to do things correctly ;-)

                If anything, make it a member variable of your class as the first suggestion of @eyllanesc. Sprinkling your code with global variables is a bad idea in any case.

                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 Reply Quote 1
                • L
                  Laurentioos last edited by

                  @SGaist I know you're right haha

                  I was struggling to understand the first suggestion still though, am I right to understand including the worker.h and declaring "worker Worker;" within the MainWindow.h is the correct way to go?

                  jsulm 1 Reply Last reply Reply Quote 0
                  • jsulm
                    jsulm Lifetime Qt Champion @Laurentioos last edited by

                    @Laurentioos said in QNetworkReply destroyed before completing:

                    am I right to understand including the worker.h and declaring "worker Worker;" within the MainWindow.h is the correct way to go?

                    yes. To be more precise: inside the MainWindow class:

                    class MainWindow : ...
                    {
                    private:
                          worker Worker;
                    

                    https://forum.qt.io/topic/113070/qt-code-of-conduct

                    1 Reply Last reply Reply Quote 0
                    • First post
                      Last post