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

Discussion :

Les fonctions dans les fonctions, comment faire ça proprement ?

  1. #1
    Membre du Club
    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
    Points : 55
    Points
    55
    Par défaut Les fonctions dans les fonctions, comment faire ça proprement ?
    Bonjour,
    Je suis en train de réaliser une fonction pour récupérer le code source d'une page internet et j'utilise donc la méthode connect() pour s'assurer que la page a fini de charger avant de passer à la suite du code. Ce que j'aimerai faire, c'est écrire du code à la suite de la méthode connect (en gros mettre le code de la méthode connect à la suite) car j'aimerai renvoyer une QVariantList. Sauf que je ne voit pas ce que le slot pourrait renvoyer d'autre que void. Voila, j'espère avoir été assez clair.

    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
    QVariantList TheMovieDB::search(const QString &title)
    {
        api_mode="search/movie";
        api_queries="&fr&query=" + title;
        api_query=api_url+api_mode+api_key+api_queries;
        view->load(QUrl(api_query));
        QObject::connect(view, SIGNAL(loadFinished(bool)), this, SLOT(resultSearch(bool))); // là je peux rien mettre à la suite car il faut attendre que la page ait chargé
    }
     
    void TheMovieDB::resultSearch(bool)
    {
        QString plainText = view->page()->currentFrame()->toPlainText();
        QJsonDocument document = QJsonDocument::fromJson(plainText.toUtf8());
        QJsonObject jsonObj = document.object();
        QJsonArray obj = jsonObj["results"].toArray();
     
        for(int i = 0; i < obj.count(); i++){ //il faudrait que le contenu de cette boucle soit renvoyé par la méthode search
            qDebug()<< obj[i].toObject()["title"].toString();
            qDebug()<< obj[i].toObject()["id"].toInt();
            qDebug()<< obj[i].toObject()["release_date"].toString();
        }
     
    }
    Merci pour votre aide.
    Cordialement

  2. #2
    Membre du Club
    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
    Points : 55
    Points
    55
    Par défaut
    J'ai cherché et on ne peut effectivement pas retourner de valeur avec le slot tel que je l'ai fait. Mais alors comment faire?

  3. #3
    Responsable Qt & Livres


    Avatar de dourouc05
    Homme Profil pro
    Ingénieur de recherche
    Inscrit en
    Août 2008
    Messages
    26 663
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur de recherche
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2008
    Messages : 26 663
    Points : 188 670
    Points
    188 670
    Par défaut


    Si je comprends bien ton problème, il suffit d'ajouter une nouvelle couche de signaux et slots : quand ton slot a fini son exécution, il émet un nouveau signal avec la valeur à retourner en argument, auquel tu connectes le code à exécuter après.

  4. #4
    Membre du Club
    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
    Points : 55
    Points
    55
    Par défaut
    C'est pas ça que je voulait dire.
    Telle qu'est présentée la fonction Search, elle contient un connect qui s'occupe de lancer la fonction resultsSearch. Ce connect sert à delayer du code de façon à attendre que la page web ait fini de charger. Or en utilisant connect, je ne peut pas renvoyer le contenu de la page web à la fonction search. Dans mon cas elle contient du code JSon donc je souhaiterais que la fonction search retourne le document JSon.
    J'espère que c'est plus clair.

    EDIT: après réflexion, ça peut correspondre à ce que je veux faire. Mais c'est assez bizarre d'utiliser la méthode connect() uniquement pour ça.

    EDIT 2: en fait non, pas moyen de renvoyer des données avec connect(). Comment ils ont pas pu penser à ça?

  5. #5
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 11
    Points : 12
    Points
    12
    Par défaut
    Salut,

    Je pense que la classe QEventLoop pourrait répondre à ta demande.

    En gros dans ton cas il fraudait faire quelque chose comme ça:


    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
     
    QVariantList TheMovieDB::search(const QString &title)
    {   
        QEventLoop loop;
        api_mode="search/movie";
        api_queries="&fr&query=" + title;
        api_query=api_url+api_mode+api_key+api_queries;
        view->load(QUrl(api_query));
        QObject::connect(view, SIGNAL(loadFinished(bool)), &loop, SLOT(quit()));
        loop.exec(); A partir de là l'exécution s'arrête et le code qui suit ne sera exécuté qu’à la fin du chargement de la page.
        // suite de ton code ...
        QString plainText = view->page()->currentFrame()->toPlainText();
        QJsonDocument document = QJsonDocument::fromJson(plainText.toUtf8());
        QJsonObject jsonObj = document.object();
        QJsonArray obj = jsonObj["results"].toArray();
     
        for(int i = 0; i < obj.count(); i++){ //il faudrait que le contenu de cette boucle soit renvoyé par la méthode search
            qDebug()<< obj[i].toObject()["title"].toString();
            qDebug()<< obj[i].toObject()["id"].toInt();
            qDebug()<< obj[i].toObject()["release_date"].toString();
        }
    }
    Je travaille sur un projet de gestion de vidéothèque et j'ai une classe presque fini qui exploite TMDB et récupère toutes les infos d'un film. Si ça t'intéresse tu peux me contacter par MP.

  6. #6
    Membre du Club
    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
    Points : 55
    Points
    55
    Par défaut
    C'est une solution qui marche mais on me l'a déconseillée. La solution consiste à utiliser deux connect():
    -le premier pour s'assurer que le téléchargement est fini
    -on rempli une variable publique avec les valeurs
    -on utilise un connect() pour renvoyer la valeur à la classe qui la demande.

    Cordialement

  7. #7
    Membre éclairé

    Profil pro
    Inscrit en
    Décembre 2013
    Messages
    397
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 397
    Points : 698
    Points
    698
    Par défaut
    dourouc05 n'a pas dit d'utiliser connect pour renvoyer des données, mais d’émettre un signal avec les données. Il n'est pas nécessaire de de créer une variable public pour faire cela
    (et ce n'est pas un oubli des connexions de ne pas pouvoir envoyer des données, cela n'a simplement pas de sens)

    En d'autres termes, tu dois avoir quelque chose comme cela :

    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
     
    class TheMovieDB ...
    public:
        void startSearch(const QString &); // pour lancer la recherche
    private slots:
        void dataAvaible(bool);                 // pas nécessaire d’être public
    signals:
        void seachFinished(SearchResult);
    };
     
    void TheMovieDB::startSearch(const QString &title)
    {
        ...
        connect(view, &QAbstractView::loadFinished, this, &TheMovieDB::dataAvaible); // utilises la syntaxe des connects de Qt5 !
    }
     
    void TheMovieDB::dataAvaible(bool)
    {
        SearchResult result;
        // remplit result avec les données reçues
        emit seachFinished(result);
    }
     
    // pour l'utiliser
    connect(db, &TheMovieDB::startSearch, this, &MainWindow::doSomeThingWithResult); // utilises la syntaxe des connects de Qt5 !
    db->search("blabla");
    Tu pourrais également faire une fonction search bloquante, mais ce n'est pas une bonne idee

  8. #8
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 11
    Points : 12
    Points
    12
    Par défaut
    Citation Envoyé par Avatar36 Voir le message
    C'est une solution qui marche mais on me l'a déconseillée sur stackoverflow. La solution consiste à utiliser deux connect():
    -le premier pour s'assurer que le téléchargement est fini
    -on rempli une variable publique avec les valeurs
    -on utilise un connect() pour renvoyer la valeur à la classe qui la demande.

    Cordialement
    Ok.

    Est-ce que tu as des détails sur la raison?

  9. #9
    Membre éclairé

    Profil pro
    Inscrit en
    Décembre 2013
    Messages
    397
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 397
    Points : 698
    Points
    698
    Par défaut
    Citation Envoyé par Caoimhin Voir le message
    Ok.

    Est-ce que tu as des détails sur la raison?
    Par ce que créer une seconde event loop va bloquer l'event loop principale et donc geler l'interface graphique pendant ce temps là.

    Généralement, il n'est pas nécessaire d'utiliser cette classe, il faut utiliser les event loop créées automatiquement dans les threads (en particulier, celui du thread principal)

  10. #10
    Membre du Club
    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
    Points : 55
    Points
    55
    Par défaut
    Généralement, il n'est pas nécessaire d'utiliser cette classe, il faut utiliser les event loop créées automatiquement dans les threads (en particulier, celui du thread principal)
    Si je te suis bien, ça veut dire qu'il vaut mieux se débrouiller avec des connect() qu'avec des loop.exec(). C'est ça?

  11. #11
    Invité
    Invité(e)
    Par défaut
    D'une manière générale, la fonction connect() sert à lier entre elles des entités indépendantes au sein de ton programme, par le biais du système de signaux/slots.

    Leur principale utilité est d'établir une communication entre différents threads, et les entités connectées restent distantes et indépendantes.
    Une fonction qui émet un signal ne fait rien d'autre qu’émettre un signal, elle ne se demande pas si le signal a été reçu par quelqu'un et moins encore si cela conduit à exécuter des instruction supplémentaires.
    Pareillement, si les slots peuvent être appelés comme des fonctions conventionnelles, lorsqu'ils sont exécutés à la suite d'un signal, il ne savent rien de l'entité qui a lancé le signal, car il ils n'ont accès qu'aux informations du signal lui-même.

    Pour visualiser le système, tu peux imaginer ton programme comme un territoire embrumé coupé par une grande rivière, et tes signaux comme des pierres, avec éventuellement des messages collés dessus (les paramètres).

    Tu as ta première troupe (view, dans ton cas) qui "catapulte" ton signal (loadFinished) par-dessus la rivière, sans voir l'autre rive plongée dans le brouillard opaque. En face, une autre troupe (le slot resultSearch) reçoit le signal, et exécute ce qui doit l'être chaque fois qu'un signal est reçu, mais sans savoir qui a lancé le signal, puisque lui non plus ne voit pas la troupe d'en face. Dans le cas présent, le retour de fonction conventionnel s'apparenterait à transmettre un message à son voisin : sans catapulte, il ne peut pas passer la rivière (le cas du multithread). Mais le problème qui se pose dans ton cas, c'est plutôt que comme ta troupe resultSearch ne sait pas qui a envoyé le signal, elle ne sait pas non plus à qui transmettre le résultat.

    Chaque troupe exécutant des instructions précises à chaque signal reçu, la fonction connect() te sert à indiquer à chaque troupe l'angle et la direction de la catapulte pour chaque type de signal qu'elle est supposée lancer, car tu es le seul, toi qui utilise cette fonction, à voir les deux rives.

    Du coup non, tu ne peux pas récupérer par voie conventionnelle le résultat d'un slot appelé par signal. La meilleure façon de le faire à mon sens est, comme l'a indiqué dourouc05, de faire en sorte que ton slot, à la fin de son exécution, envoie un signal transportant le résultat de son calcul, signal que tu connecteras à un slot chargé de traiter ces données.

Discussions similaires

  1. Réponses: 0
    Dernier message: 25/02/2012, 10h02
  2. Réponses: 3
    Dernier message: 06/08/2009, 17h09
  3. Réponses: 4
    Dernier message: 11/09/2006, 16h55
  4. Les polices dans les tables et les requêts
    Par zooffy dans le forum Access
    Réponses: 3
    Dernier message: 21/06/2006, 11h06

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