2015-03-25 3 views
0

Je fais une QCoreApplication Qt5 pour le téléchargement de fichiers à partir de serveurs FTP (commencé à HTTP, maintenant commuté).Façon correcte de fermer QCoreApplication

Je rencontre un problème lorsque mon programme doit être fermé. Après avoir ajouté exit(0) dans downloader.cpp, mon programme se termine maintenant, mais je reçois l'erreur suivante:

QWaitCondition: Détruit alors que les discussions sont toujours en attente.

Mon code est le suivant:

main.cpp 

#include <QCoreApplication> 
#include <downloader.h> 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    Downloader d; 
    d.doDownload(); 

    a.exec(); 
} 


**downloader.cpp** 

#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.fao.org/Public/GIEWS/windisp/40manual/wd4en.pdf"))); 
} 


void Downloader::replyFinished (QNetworkReply *reply) 
{ 

    if(reply->error()) { 
     qDebug() << "ERROR!"; 
     qDebug() << reply->errorString(); 
    } 
    else 

    { 
     qDebug() << "Download finished!"; 

     QFile *file = new QFile("C:/Users/jelicicm/Desktop/wd4en.pdf"); 

     if(file->open(QFile::Append)) 
     { 
      file->write(reply->readAll()); 
      file->flush(); file->close(); 
      qDebug() <<"Downloaded file size:" <<(file->size())/1024<<"KB"; 
     } 
     delete file; 
    } 

    reply->deleteLater(); 
    exit(0); 

} 

Je reçois la sortie suivante:

Télécharger Fini! Taille du fichier téléchargé ... QWaitCondition: Détruit alors que les threads sont toujours en attente.

Pour autant que je puisse le remarquer, tout ce que j'ai imaginé est fait. Le fichier est téléchargé et sa taille est présentée. Mais je suppose que cette erreur doit signifier quelque chose. Quelqu'un peut-il m'expliquer ce qu'est cette erreur, pourquoi cela se produit et comment le réparer?

+2

Essayez d'utiliser qApp-> exit (0).Puisque votre classe de téléchargeur est un QObject, vous pouvez également créer et émettre un signal à la place de l'appel de sortie pour quelque chose comme "complete" et dans "complete" du téléchargeur principal connect à l'emplacement "QCoreApplication :: quit()". – iminyourbrain

+0

qApp-> exit (0) ne donne rien de bon. va essayer de faire quelque chose avec la connexion de deux signaux ... Thaks pour votre réponse! – Rorschach

Répondre

6

Vous avez des problèmes avec votre code. Vous traitez Qt comme s'il était de nature procédurale alors qu'il est en réalité piloté par une boucle principale. Tout d'abord, il est faux d'appeler qApp->exit(0) avant que la boucle QApplication ne soit démarrée. Selon Qt, "Si la boucle d'événements n'est pas en cours d'exécution, cette fonction ne fait rien." Votre boucle d'événements ne fonctionne pas encore parce que vous avez appelé doDownload avant que vous avez appelé exec

En second lieu, au moment où vous avez exécuté QApplication::exec, vous n'avez pas encore créé de fenêtres de niveau supérieur ou des événements à l'expédition. Je ne suis pas sûr de ce qui est censé se produire lorsque vous appelez exec sans aucun travail à faire. Sémantiquement, bien sûr, l'appel à exec ne fait rien. Techniquement ... peut-être que cela pourrait conduire à des erreurs de thread. Encore une fois, je ne suis pas sûr, mais je sais que vous n'êtes pas censé utiliser exec de cette manière.

Exécutez votre boucle d'événement principal avant en faisant tous vos trucs Qt de fantaisie. Cela permet à Qt d'appeler dans votre code. Ajouter un emplacement, doDownload et un signal, finished à votre Downloader.

class Downloader : public QObject 
{ 
    Q_OBJECT 

public: 
    Downloader(QObject * parent = nullptr); 

private slots: 
    void doDownload(); 

signals: 
    void finished(); 
} 

... 

void Downloader::doDownload() 
{ 
    // Same implementation as before 
    // Emit signal when finished 
    emit finished(); 
} 

Ensuite, appelez votre emplacement après l'inversion de contrôle a été mis en place en appelant exec et à partir de la boucle principale:

#include <QCoreApplication> 
#include "Downloader.h" 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    Downloader d; 

    // Quit application when work is finished 
    QObject::connect(&d, SIGNAL(finished()), &a, SLOT(quit())); // changed the 
    //variable name 'app' to 'a' 

    // Run the user-hook (doDownload) from the application event loop. 
    QTimer::singleShot(0, &d, SLOT(doDownload())); 

    return a.exec(); 
} 

Maintenant Qt appellera dans votre code. Au lieu de quitter explicitement l'application, simplement emit finished() et tout devrait être nettoyé correctement.

S'il vous plaît laissez-moi savoir si cela résout votre problème. Sinon, il peut y avoir d'autres poissons à frire.

+1

Merci pour votre réponse! J'ai obtenu mon code pour travailler grâce à vous. J'ai 'doDownload()' défini comme un slot public, et j'envoie 'emit' le signal de 'replyFinished'. Je n'ai pas lu sur 'QTimer' parce que je ne pensais pas qu'il puisse être utilisé de cette façon. Apprendra maintenant. Encore une fois, merci! – Rorschach

+1

Un appel 'exec()' ne fait que tourner la boucle d'événements. S'il n'y a aucun événement à venir, la boucle se trouve juste là, les attendant, pour toujours. C'est inoffensif mais inutile. Un cas minimum serait '#include int main (int argc, char ** argv) {application QCoreApplication (argc, argv); return app.exec(); } '- ça pendra simplement pour toujours. –