IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Qt Discussion :

Retarder une boucle for


Sujet :

Qt

  1. #1
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 218
    Par défaut Retarder une boucle for
    Bonjour,
    Comme dit dans le titre, j'ai besoin de delayer une boucle for (ou d'utiliser un système du même genre). Je vous explique tout:
    J'ai réalisé un QThread (car opération longue) dans lequel je récupère des chemins de fichiers vidéos à partir d'un dossier. Puis dans une boucle for, je demande de récupérer les informations du films sur internet (qnetworkmanager + signal et slot) depuis la boucle for. Sauf que voila ce qui se passe:
    -Premier passage dans la boucle
    -Récupération du nom du film depuis le chemin du fichier
    -Récupération des données sur internet (étape 1 sur 6)
    -Deuxième passage dans la boucle (donc la récupération des données du premier film est interrompue). Et c'est pareil pour tous donc je récupère rien

    Voila le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #include "moviethread.h"
    #include "generalfunctions.h"
    #include "cpp.panneauConfiguration/Parametres.h"
    #include "cpp.infos/Bdd.h"
     
    MovieThread::MovieThread(QObject *parent):QThread(parent)
    {
    }
     
    void MovieThread::run()
    {
        bdd *db = new bdd;
    qDebug()<<"DEBUT DU THREAD";
        Parametres *settings = new Parametres;
     
        for(int j=0; j<settings->listeDossiersFilms.size();j++)
        {
            QStringList list = GeneralFunctions::listFiles(settings->listeDossiersFilms[j], true); //Liste les fichiers films
            for (int i=0; i<list.size();i++)
            {
                Movie *movie = new Movie;
                movie->md5 = GeneralFunctions::hashMD5(list[i]);
                movie->path = list[i];
                movie->title = QFileInfo(list[i]).baseName();
                movie->getInfos(); //Récupération des données sur internet
                db->addMovie(movie); //on ajoute le film dans la base de données
            }
        }
    }
     
    MovieThread::~MovieThread()
    {
    }
    Cordialement

  2. #2
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 218
    Par défaut
    Bon mon sujet n'excite pas les foules. Je vais tenter de reformuler tout ça.
    Je souhaite faire un QThread qui attend qu'un signal soit émit pour se terminer.
    Imaginons que je veuilles télécharger des pages internet grâce à l'outil QNetworkManager. Je veux télécharger la première entièrement et alors seulement passer à la deuxième, etc...
    Comment est-ce qu'on ferait ça dans un QThread? Pouvez-vous me montrer un bout de code?

  3. #3
    Membre éprouvé
    Avatar de ymoreau
    Homme Profil pro
    Ingénieur étude et développement
    Inscrit en
    Septembre 2005
    Messages
    1 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur étude et développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 154
    Par défaut
    De ce que je comprends tu as juste besoin de bloquer l'exécution de ton code en attendant que le QNetworkManager télécharge les infos du film ? movie->getInfos(); avec cet appel là.
    La fonction (ou en interne dans QNetworkManager) crée donc un troisième thread pour l'opération ? Il faut le détail de tes appels non bloquants pour savoir comment s'y prendre, c'est à dire le code de ta fonction qui récupère les infos.

  4. #4
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 218
    Par défaut
    Bien, alors allons-y. Attention le code est long:
    morceau de Movie.cpp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    void Movie::getInfos()
    {
        QObject::connect( tmdb , SIGNAL( dataRetrieved() ) , this , SLOT( updateDatas() ));
        tmdb->search(title);
    }
     
     
    void Movie::updateDatas()
    {
        title = tmdb->t_infosList["title"].toString();
        id = tmdb->t_infosList["id"].toInt();
        releaseDate = tmdb->t_infosList["release_date"].toDate();
        note = tmdb->t_infosList["note"].toInt();
        synopsis = tmdb->t_infosList["overview"].toString();
        backdropPath = tmdb->t_infosList["backdrop"].toString();
        backdropMD5 = GeneralFunctions::hashMD5(tmdb->t_infosList["backdrop"].toString());
        posterPath = tmdb->t_infosList["poster"].toString();
        posterMD5 = GeneralFunctions::hashMD5(tmdb->t_infosList["poster"].toString());
        collection = tmdb->t_infosList["collection"].toString();
        QStringList genres = tmdb->t_infosList["genres"].toStringList();
        genre = genres[0];
        for(int i=0 ; i<genres.size() ; i++)
        {
            genre =genre + ", " + genres[i];
        }
        emit dataUpdated();
    }
    tmdb.cpp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    TheMovieDB::TheMovieDB(QObject *parent) : QObject(parent)
    {
        t_api_key="?api_key=**************";
        t_api_url="http://api.themoviedb.org/3/";
        t_manager = new QNetworkAccessManager;
        t_resultID=0;
    }
     
    //******************************************* Search from Title ******************************************************
    void TheMovieDB::search(const QString &title)
    {
        qDebug()<<"étape 1";
        t_title=GeneralFunctions::prepareString(title);
        t_api_query= t_api_url + "search/movie" + t_api_key + "&language=fr&query=" + t_title;
        QObject::connect(t_manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(readTitleSearch(QNetworkReply *)));
        t_manager->get(QNetworkRequest(QUrl(t_api_query)));
    }
     
    //On lit le résultat de la recherche par titre
    void TheMovieDB::readTitleSearch(QNetworkReply *reply)
    {
        qDebug()<<"étape 2";
        QString source = reply->readAll();
        QJsonDocument document = QJsonDocument::fromJson(source.toUtf8());
        QJsonObject jsonObj = document.object();
        QJsonArray obj = jsonObj["results"].toArray();
        QDate date;
     
        int distance=GeneralFunctions::distanceDL(t_title , obj[0].toObject()["title"].toString());
        t_resultID=obj[0].toObject()["id"].toInt();
        int distanceToBeCompared=0;
     
        for(int i = 1; i < obj.count(); i++){
            if(date.fromString(obj[i].toObject()["release_date"].toString(), "yyyy-MM-dd") < QDate::currentDate())
            {
                distanceToBeCompared=GeneralFunctions::distanceDL(t_title , obj[i].toObject()["title"].toString());
                if(distance > distanceToBeCompared)
                {
                    distance=distanceToBeCompared;
                    t_resultID=obj[i].toObject()["id"].toInt();
                }
            }
        }
        //on lance la suite
        searchID(t_resultID);
    }
     
    //******************************************* Search from ID ******************************************************
    void TheMovieDB::searchID(const int &id)
    {
        qDebug()<<"étape 3";
        t_manager->disconnect(t_manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(readTitleSearch(QNetworkReply *)));
        t_api_query=t_api_url+"movie/"+QString::number(id)+t_api_key+"&language=fr";
        QObject::connect(t_manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(readIDSearch(QNetworkReply *)));
        t_manager->get(QNetworkRequest(QUrl(t_api_query)));
    }
     
     
    //Faire un téléchargement automatique des images
    //poster_path, backdrop_path
    void TheMovieDB::readIDSearch(QNetworkReply *reply)
    {
        qDebug()<<"étape 4";
        t_infosList.clear();
        QString source = reply->readAll();
        QJsonDocument document = QJsonDocument::fromJson(source.toUtf8());
        QJsonObject jsonObj = document.object();
        QJsonArray objGenres = jsonObj["genres"].toArray();
     
        QStringList genresList;
        for(int i = 0; i < objGenres.count(); i++){
            genresList.append(objGenres[i].toObject()["name"].toString());
        }
     
        t_infosList["title"] =jsonObj["title"].toString();
        t_infosList["genres"]=genresList;
        t_infosList["id"] =jsonObj.value("id").toInt();
        t_infosList["release_date"] = QDate::fromString(jsonObj.value("release_date").toString(),"yyyy-MM-dd");
        t_infosList["overview"] = jsonObj.value("overview").toString();
        t_infosList["note"] = jsonObj.value("vote_average").toDouble();
        t_infosList["collection"]=jsonObj["belongs_to_collection"].toObject()["name"].toString();
        t_posterURL = jsonObj["poster_path"].toString();
        getBackdrop(t_infosList["title"].toString() , jsonObj["backdrop_path"].toString());
    }
     
    //******************************************* DOWNLOAD BACKDROP ******************************************************
    void TheMovieDB::getBackdrop(const QString &pictureName, const QString &pictureUrl)
    {
        qDebug()<<"étape 5";
        t_manager->disconnect(t_manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(readIDSearch(QNetworkReply *)));
        t_picturePath= "./backdrop/" + pictureName + ".jpg";
        t_infosList["backdrop"]=t_picturePath;
        QString url="http://image.tmdb.org/t/p/w1920"+pictureUrl;
        QObject::connect(t_manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(saveBackdrop(QNetworkReply*)));
        t_manager->get(QNetworkRequest(QUrl(url)));
    }
     
    void TheMovieDB::saveBackdrop(QNetworkReply *reply)
    {
        qDebug()<<"étape 6";
        QFile* file = new QFile;
        file->setFileName(t_picturePath);
        file->open(QIODevice::WriteOnly);
        file->write(reply->readAll());
        getPoster(t_infosList["title"].toString() , t_posterURL);
    }
     
    //******************************************* DOWNLOAD POSTER *******************************************************
    void TheMovieDB::getPoster(const QString &pictureName, const QString &pictureUrl)
    {
        qDebug()<<"étape 7";
        t_manager->disconnect(t_manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(saveBackdrop(QNetworkReply *)));
        t_picturePath= "./poster/" + pictureName + ".jpg";
        t_infosList["poster"]=t_picturePath;
        QString url="http://image.tmdb.org/t/p/w1920"+pictureUrl;
        QObject::connect(t_manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(savePoster(QNetworkReply *)));
        t_manager->get(QNetworkRequest(QUrl(url)));
    }
     
    void TheMovieDB::savePoster(QNetworkReply *reply)
    {
        qDebug()<<"étape 8";
        QFile* file = new QFile;
        file->setFileName(t_picturePath);
        file->open(QIODevice::WriteOnly);
        file->write(reply->readAll());
        t_manager->disconnect(t_manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(savePoster(QNetworkReply *)));
        emit dataRetrieved();
    }
    Moi ce que je cherche à faire c'est enchaîner les getInfos() les uns après les autres sachant que je ne sais pas à l'avance combien il y en a. L'idéal eu été que je connecte la fin du premier getInfo() au début du deuxième. Mais le programme n'attend pas que les données soient récupérées.

  5. #5
    Membre éprouvé
    Avatar de ymoreau
    Homme Profil pro
    Ingénieur étude et développement
    Inscrit en
    Septembre 2005
    Messages
    1 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur étude et développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 154
    Par défaut
    Je ne vois pas d'intérêt à vouloir faire les requêtes les unes après les autres plutôt qu'en parallèle. Ta conception me semble un peu compliquée, le système Qt de signal slot permet justement de ne pas s'embêter à attendre et synchroniser des traitements asynchrones (sauf cas particuliers mais je n'ai pas l'impression que tu aies ce besoin là). Qu'est-ce qui est réellement long dans ton traitement ? l'attente de retour des requêtes ou le parcours des fichiers et les traitements en base sont également assez longs ? Dans le premier cas tu pourrais sans doute te passer de faire un second thread. Sinon tu pourrais aussi lancer dans autant de thread que nécessaire tous les téléchargements de données de film en parallèle, QtConcurrent permet ce genre de choses, mais ça t'obligerait à revoir pas mal ce que tu as fait.

    Sinon pour répondre rapidement à ta question de départ, une fois que tu as lancé tes requêtes t_manager->get(... tu dois attendre que le QNetworkReply retourné soit finished avant de passer à la suite. Soit en faisant un while(reply->isFinished()); soit plus propre en créant une QEventLoop :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    QEventLoop loop;
    connect(netReply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();
    // here you have done.

  6. #6
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 218
    Par défaut
    Merci je vais jeter un oeil à cette classe QtConcurrent. L'intérêt que je voyais à faire les un après les autres c'est donner facilement le pourcentage d'avancement global (film 1/700 par exemple) et surtout ça m'évitais de déclarer 700 variables films d'un seul coup. Et surtout, ça risque d'être l'anarchie au moment d'enregistrer les données dans la bdd. Si il y en a deux en même temps, je ne sais pas ce qu'il va se passer. ça va surement planter.

  7. #7
    Membre éprouvé
    Avatar de ymoreau
    Homme Profil pro
    Ingénieur étude et développement
    Inscrit en
    Septembre 2005
    Messages
    1 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur étude et développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 154
    Par défaut
    Le pourcentage d'avancement fonctionne aussi si tu traites 3 ou 8 films en parallèle, chacun avertira ton application qu'il s'est terminé et ça incrémentera ton compteur du total de films déjà traités.
    Par contre effectivement, qui dit parallèle dit synchronisation et protection des données partagées, ça complique ta conception. Il faut protéger l'accès à ton compteur pour l'avancement, que deux films ne viennent pas le modifier en même temps et également protéger les accès en base, que ta classe qui gère la sauvegarde n'en sauvegarde pas plusieurs en même temps. Si tu n'as pas de connaissances en programmation multithread ça peut être un peu complexe, ça dépend du temps que tu as devant toi ;-)

  8. #8
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2014
    Messages
    218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2014
    Messages : 218
    Par défaut
    J'ai un temps illimité étant donné que c'est une application pour moi seul. Je suis partant pour apprendre de nouvelles choses
    Du coup qu'est-ce qu'il faut que je regarde pour savoir ce que je dois faire?

  9. #9
    Membre éprouvé
    Avatar de ymoreau
    Homme Profil pro
    Ingénieur étude et développement
    Inscrit en
    Septembre 2005
    Messages
    1 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur étude et développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 154
    Par défaut
    C'est un sujet plus vaste que le sujet que tu as créé sur le forum. Tu peux regarder des cours généraux sur la programmation multithread (tu trouveras plein de choses sur le net), la doc de Qt explique assez bien les différentes techniques offertes par le framework. Tu peux regarder dans l'aide il y a un chapitre sur le multithread.

Discussions similaires

  1. Shell - Erreur dans une boucle for
    Par claralavraie dans le forum Linux
    Réponses: 4
    Dernier message: 11/01/2006, 13h45
  2. : remplir des zones de texte avec une boucle For
    Par Haro_GSD dans le forum Access
    Réponses: 3
    Dernier message: 20/09/2005, 21h23
  3. Problème avec une DLL dans une boucle For
    Par BraDim dans le forum Langage
    Réponses: 5
    Dernier message: 20/09/2005, 12h22
  4. [batch] incrémentation dans une boucle for
    Par bart64 dans le forum Scripts/Batch
    Réponses: 4
    Dernier message: 08/09/2004, 20h05
  5. Réponses: 3
    Dernier message: 06/07/2004, 10h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo