[Solved] Qt 5.1 file not downloading from web on first attempt



  • I have a problem that occurs with Qt 5.1 (Linux Mint 15 32 bit in Virtualbox) that didn't happen with Qt 5.0.2. I have 2 classes that respond to an update button each, to download an updated input file for each class from the web. The first press of either download button returns a 0 byte file, with button any subsequent button presses working fine, while the GUI app is still running. Restart the app and the problem re-occurs. Here's the download procedure I'm using in each of my classes:

    @void class1::downloadFile(const QString &url, const QString &aPathInClient)
    {
    QNetworkAccessManager m_NetworkMngr;// = new QNetworkAccessManager(this);
    QNetworkReply *reply= m_NetworkMngr.get(QNetworkRequest(url));
    QEventLoop loop;
    QObject::connect(reply, SIGNAL(finished()),&loop, SLOT(quit()));
    loop.exec();
    QUrl aUrl(url);
    QFileInfo fileInfo=aUrl.path();

    QFile file(aPathInClient+"/"+fileInfo.fileName());
    file.open(QIODevice::WriteOnly);
    file.write(reply->readAll());
    file.close();

    reply->deleteLater();
    }
    @

    Any insight into this problem would be much appreciated. I have a 64 bit Linux Mint 15 virtual machine that I haven't tried it on yet, and also I haven't tried it on my Windows 7 64 bit host, using msvc2012 32bit. Any code change suggestions are welcome. Like I said, everything worked fine with Qt 5.0.2, both Linux virtual machines, and the Windows 7 host. Thanks in advance for any replies.

    Edit: I found out it also happens with Qt 5.0.2


  • Moderators

    [quote]
    @
    QObject::connect(reply, SIGNAL),&loop, SLOT));
    @
    [/quote]That won't compile. Please copy + paste your actual code.

    Also, there's no need to create an event loop. Just connect the QNetworkReply::finished() signal to a slot that writes your file.



  • I fixed the code on the original post. I am now trying to use a class member defined slot, without an event loop, but the slot never gets called (I verified this by putting a QMessageBox inside the slot, which never gets dispalyed).

    Here's the code with class member defined slot:

    class1.h

    @
    class class1: public QObject
    {

    Q_OBJECT

    public slots:

    void onRequestCompleted();

    public:

    QString df_url;
    QString df_path;

    public:

    void downloadFile(const QString &url, const QString &aPathInClient);

    };
    @

    class1.cpp
    @
    void class1::downloadFile(const QString &url, const QString &aPathInClient)
    {

    df_url = url;
    df_path = aPathInClient;

    QNetworkAccessManager m_NetworkMngr;
    QNetworkReply *reply = m_NetworkMngr.get(QNetworkRequest(url));
    QObject::connect(reply, SIGNAL(finished()), this, SLOT(onRequestCompleted()));

    reply->deleteLater();
    }

    void class1::onRequestCompleted( )
    {

    QString url2;
    QString aPathInClient2;

    url2 = df_url;
    aPathInClient2 = df_path;

    QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());

    QUrl aUrl(url2);
    QFileInfo fileInfo=aUrl.path();

    QFile file(aPathInClient2+"/"+fileInfo.fileName());
    file.open(QIODevice::WriteOnly);
    file.write(reply->readAll());
    file.close();
    reply->deleteLater();

    }

    @

    Any ideas on why the slot isn't being called, anyone?


  • Lifetime Qt Champion

    Hi,

    You are deleting reply to early. deleteLater does not mean "delete when everything is done".

    You should delete the reply once you've got the data.

    Hope it helps



  • I got the file to download using the following code changes:

    @void class1::downloadFile(const QString &url, const QString &aPathInClient)
    {

    df_url = url;
    df_path = aPathInClient;
    
    QNetworkAccessManager *m_NetworkMngr = new    QNetworkAccessManager(this&#41;;
    
    QObject::connect(m_NetworkMngr, SIGNAL(finished(QNetworkReply*&#41;&#41;, this, SLOT(onRequestCompleted(QNetworkReply*)));
    
    m_NetworkMngr->get(QNetworkRequest(url));
    

    }

    void class1::onRequestCompleted(QNetworkReply *reply ) {

    QString url2;
    QString aPathInClient2;
    
    url2 = df_url;
    aPathInClient2 = df_path;
    
    
    QUrl aUrl(url2);
    QFileInfo fileInfo=aUrl.path();
    
    QFile file&#40;aPathInClient2+"/"+fileInfo.fileName(&#41;&#41;;
    file.open(QIODevice::WriteOnly&#41;;
    file.write(reply->readAll(&#41;);
    file.close();
    

    }@

    But now it doesn't download the first time, only on subsequent attempts. The initial event loop approach works on both my Windows 7 host, and in the Windows 7 guest in Virtualbox. I don't know why the event loop approach doesn't work in my Linux Mint guest in Virtualbox. Anyone got a Linux machine that can try the code - maybe it's something to do with Virtualbox, or possibly the Linux Mint guest in Virtualbox?

    Edit: the event loop approach is not working on Windows 7, with the same problem: no download on first attempt. With both the loop approach and the member defined slot approach, I made the network manager varaible a class variable to help, but no effect on the problem. I also removed the deleteLater line to see if it helps, but no change.



  • I finally got it to work. There was a problem with consistent downloads from my original download site. Switched web sites to download from and the problem was solved. Here's the code I'm using:

    @

    class1.h

    class class1: public QObject
    {

    //There's a lot more to the class, but here are the pertinent parts
    
    Q_OBJECT
    

    public slots:

    void onRequestCompleted();

    public:

     QString df_url;
     QString df_path;
     QNetworkAccessManager *m_NetworkMngr;
     QNetworkReply *reply;
    

    public:

     void downloadFile&#40;const QString &url, const QString &aPathInClient&#41;;
    

    };

    class1.cpp

    void class1::downloadFile(const QString &url, const QString &aPathInClient)
    {

    df_url = url; //class variable
    df_path = aPathInClient; //class variable

    m_NetworkMngr = new QNetworkAccessManager(this); //class variable

    reply= m_NetworkMngr->get(QNetworkRequest(url)); //class variable

    QObject::connect(reply, SIGNAL(finished()), this, SLOT(onRequestCompleted()));

    }

    void class1::onRequestCompleted() {

    QString url2;
    QString aPathInClient2;
    
    url2 = df_url;
    aPathInClient2 = df_path;
    

    QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());

    QUrl aUrl(url2);
    QFileInfo fileInfo=aUrl.path();

    QFile file(aPathInClient2+"/"+fileInfo.fileName());
    file.open(QIODevice::WriteOnly);
    file.write(reply->readAll());
    file.close();

    }@

    The downloadFile procedure parameters:

    url - string url of file I'm downloading
    aPathInClient - string location of the folder that contains the file I'm updating

    downloadFile gets called by a procedure that gets called by pressing a button. The entire class gets instanced with the button and then gets destroyed when the slot for the button completes. So the reply and network manager objects get destroyed when that happens.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.