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. [Solved] Cannot download using QNetworkAccessManager
Forum Updated to NodeBB v4.3 + New Features

[Solved] Cannot download using QNetworkAccessManager

Scheduled Pinned Locked Moved General and Desktop
14 Posts 2 Posters 3.5k 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.
  • I Offline
    I Offline
    igorland
    wrote on last edited by
    #5

    sierdzio. Thank you again. Can you please elaborate what exactly I am doing wrong? Cheers!

    1 Reply Last reply
    0
    • sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #6

      @
      Downloader d;
      d.doDownload();

      QString metarData;
      // This is WAY too soon!
      metarData = d.getData();
      @

      instead of getting the data in the very same method, you need to wait until the reply comes. Either use a forever loop (ugly solution!), or, just like you are doing in Downloader: respond to replyFinished().

      (Z(:^

      1 Reply Last reply
      0
      • I Offline
        I Offline
        igorland
        wrote on last edited by
        #7

        sierdzio,

        Sorry, I am trying to understand what you mean by "like you are doing in Downloader: respond to replyFinished()."

        I have been searching more on this and another suggestion that I have come across with was to put the d object on the heap. I changed it to:

        [code]
        Downloader* d = new Downloader;
        d->doDownload();

        QString metarData;
        metarData = d->getData();
        ui->plainTextEdit->setPlainText(metarData);
        

        [/code]

        Still no luck... Sorry for being so n00b.. ))

        1 Reply Last reply
        0
        • sierdzioS Offline
          sierdzioS Offline
          sierdzio
          Moderators
          wrote on last edited by
          #8

          When the button is clicked, only send the request (doDownload). Then getData in a slot connected to finished(). You need to refactor the code bit. Here is a small helper:
          @
          // Downloader
          signals:
          void downloadFinished(Downloader *d);
          ...
          void Downloader::replyFinished (QNetworkReply *reply) {
          ...
          emit downloadFinished(this);
          }

          // MainWindow
          void MainWindow::on_pushButton_clicked()
          {
          Downloader *d = new Downloader(this);
          connect (d, SIGNAL(downloadFinished(Downloader *)), this, SLOT(someSlot(Downloader *)));
          d->doDownload();
          ...
          }
          ...
          void MainWindow::someSlot(Downloader *down)
          {
          QString metarData;
          metarData = down->getData();
          // Optional:
          down->deleteLater();
          }
          @

          (Z(:^

          1 Reply Last reply
          0
          • I Offline
            I Offline
            igorland
            wrote on last edited by
            #9

            sierdzio. You do belong to the Hall of Fame for your support and knowledge. I am still trying to nail it down. This is what I have now:

            [code]
            #include "Downloader.h"

            Downloader::Downloader(QObject *parent) :
            QObject(parent)
            {
            }

            void Downloader::doDownload()
            {
            manager = new QNetworkAccessManager(this);
            connect(manager, SIGNAL(finished(QNetworkReply*)),this, SLOT(replyFinished(QNetworkReply*)));
            manager->get(QNetworkRequest(QUrl("ftp://ftp.com/ftp.TXT")));

            }

            void Downloader::replyFinished (QNetworkReply *reply)
            {
            if(reply->error())
            {
            qDebug() << "ERROR!";
            qDebug() << reply->errorString();
            }
            else
            {
            dataByte = reply->readAll();
            emit downloadFinished(this);
            reply->deleteLater();
            }
            }

            void Downloader::downloadFinished(Downloader *dfinished)
            {
            QString dataStr(dataByte);
            dataFinal = dataStr;
            dfinished->deleteLater();
            }

            QString Downloader::getData()
            {
            return dataFinal;
            }

            [/code]

            MainWindow.cpp
            [code]
            #include "mainwindow.h"
            #include "ui_mainwindow.h"
            #include "Downloader.h"

            MainWindow::MainWindow(QWidget *parent) :
            QMainWindow(parent),
            ui(new Ui::MainWindow)
            {
            ui->setupUi(this);
            }

            MainWindow::~MainWindow()
            {
            delete ui;
            }

            void MainWindow::on_pushButton_clicked()
            {
            d = new Downloader(this); // declared in header
            connect(d, SIGNAL(downloadFinished(Downloader *)), this, SLOT(someSlot(Downloader *)));
            d->doDownload();

            ui->plainTextEdit->setPlainText(metarData);
            

            }

            void MainWindow::someSlot(Downloader* down)
            {
            metarData = d->getData();
            down->deleteLater();
            }
            [/code]

            Now, I get a weird error saying that
            [code]
            multiple definition of Downloader::downloadFInished(Downloader*)
            first define here
            [/code]

            Weird, because I only have it defined in Downloader.h
            [code]
            #ifndef DOWNLOADER_H
            #define DOWNLOADER_H

            #include <QObject>
            #include <QNetworkAccessManager>
            #include <QNetworkRequest>
            #include <QNetworkReply>
            #include <QUrl>
            #include <QDateTime>
            #include <QFile>
            #include <QDebug>
            #include <QEventLoop>

            class Downloader : public QObject
            {
            Q_OBJECT
            public:
            explicit Downloader(QObject *parent = 0);
            void doDownload();
            QString getData();

            signals:
            void downloadFinished(Downloader *dfinished);

            public slots:
            void replyFinished (QNetworkReply *reply);

            private:
            QNetworkAccessManager *manager;
            QByteArray dataByte;
            QString dataFinal;
            };

            #endif // DOWNLOADER_H
            [/code]

            I love Qt, but it is so discouraging to spend many days on something that took me a day to figure out how to do it in libcurl and Java.

            sierdzio. Thank you again!

            1 Reply Last reply
            0
            • sierdzioS Offline
              sierdzioS Offline
              sierdzio
              Moderators
              wrote on last edited by
              #10

              If you want easy, go with QHttp or QFtp ;) QNAM is powerful, but also more complicated. The asynchronous paradigm is much better, but also more complicated and harder to get.

              In your case, you've hit a small detail that some people new to Qt do stumble upon: a signal is not a method, only the slots need implementation. So, you should delete all this:
              @
              // Delete!
              void Downloader::downloadFinished(Downloader *dfinished)
              {
              QString dataStr(dataByte);
              dataFinal = dataStr;
              dfinished->deleteLater();
              }
              @

              And only leave this line in the header file:
              @
              signals:
              void downloadFinished(Downloader *dfinished);
              @

              (Z(:^

              1 Reply Last reply
              0
              • I Offline
                I Offline
                igorland
                wrote on last edited by
                #11

                sierdzio. You are the MAN! Thank you. Now the file is getting downloaded. I see it in qDebug. One problem still remains though due the asynchronous process, I believe. The thing is that when in the following code:

                [code]
                void MainWindow::on_pushButton_clicked()
                {
                d = new Downloader(this);
                d->doDownload();
                connect(d, SIGNAL(downloadFinished(Downloader *)), this, SLOT(someSlot(Downloader *)));

                qDebug() << "MetarData: " <&lt; metarData;
                ui-&gt;plainTextEdit->setPlainText(metarData);
                

                }

                void MainWindow::someSlot(Downloader* down)
                {
                metarData = d->getData();
                down->deleteLater();
                }
                [/code]

                when I do this:
                [code]
                ui->plainTextEdit->setPlainText(metarData);
                [/code]

                it does not do anything. Apparently, it does not wait for the file to be first downloaded and goes straight to setPlainText because

                [code]
                qDebug() << "MetarData: " << metarData
                [/code]

                returns an empty string. In my main application, where metarData is further passed to other functions, I even get a CTD.
                I thought that connect should take care of this and the code would wait for the full data to be downloaded first.

                Thanks!

                1 Reply Last reply
                0
                • I Offline
                  I Offline
                  igorland
                  wrote on last edited by
                  #12

                  On the other hand, I can move it to the someSlot function and let it be there. Anyways, thanks a lot for your great help!

                  1 Reply Last reply
                  0
                  • sierdzioS Offline
                    sierdzioS Offline
                    sierdzio
                    Moderators
                    wrote on last edited by
                    #13

                    You assign the variable at the wrong time. Do this instead:
                    @
                    void MainWindow::someSlot(Downloader* down)
                    {
                    metarData = d->getData();
                    ui->plainTextEdit->setPlainText(metarData);
                    down->deleteLater();
                    }
                    @

                    (Z(:^

                    1 Reply Last reply
                    0
                    • I Offline
                      I Offline
                      igorland
                      wrote on last edited by
                      #14

                      Yes. Thanks a lot. Very much appreciated.

                      1 Reply Last reply
                      0

                      • Login

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