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 :

Signaux et slots comme Qt


Sujet :

Qt

  1. #1
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut Signaux et slots comme Qt, ou autres méthodes
    Bonjour,
    je réalise une application avec la SDL, et j'ai crée des boutons. Je voudrais que lorsqu'un bouton est pressé cela appelle la bonne fonction.

    La solution : Signals and Slots de Qt me parait intéressante et j'aimerais pouvoir l'implémenter.

    Pour cela, je pensais faire une classe Connecteur et une fonction connect qui prend l'objet emetteur, la méthode qui envoie le signal, l'objet recepteur, et la méthode qui doit recevoir le signal.

    Idée pour la classe Connecteur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    template <class Emetteur, class Recepteur>
    class Connecteur
    {
        Emetteur & emetteur;
        Connecteur & connecteur;
        // Et la problème je ne peux pas déclarer mes pointeurs sur des méthodes
        // car je peux avoir void, int, ...
    };
    De plus admettons que je puisse faire la déclaration de mes méthodes (c'est peux etre possible en s'inspirant de mem_fun), je voudrais un conteneur de pointeurs sur mes objets, et de pointeurs sur mes méthodes pour pouvoir y accéder de cette maniere :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    // admettons que ce code marche
    Bouton bouton;
    Receveur receveur;
    connect(&bouton, &bouton::onCLic, &receveur, &Receveur::methode);
    onClic a le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void Bouton::onClic()
    {
        Connecteur::send(this, &Bouton::onClic);
    }
    et send :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void Connecteur::send(Emetteur & emetteur, PtrEMethode methode) // PtrEMethode est un typedef pour un pointeur de methode de emetteur
    {
        Recepteur * objet = connecteurs[emetteur][methode].first;
        PtrRMethode * methodeR =  connecteurs[emetteur][methode].second;
        objet->(*methodeR)();
    }
    Avec ce code je dois forcement avoir une methode qui n'a pas de parametres donc c'est très limité, mais bon le problème est que cette idée d'implémentation ne me parait pas réalisable.

    J'aimerais avoir votre avis, et savoir comment vous feriez pour implémenter ceci, ou s'il y a une meilleur méthode que celle utilisée par Qt faite le moi savoir.

    D'avance merci.

  2. #2
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Salut,

    Tu as jeté un oeil sur boost.signals ?

    MAT.

  3. #3
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut
    Je vais me pencher de ce pas sur le lien que tu viens de me donner Mat007.

    Merci !

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Je n'ai jamais compris comment on pouvait même avoir l'idée d'un truc comme le système de Qt.

    C'est simple, quand un événement se produit tu veux appeler un foncteur. Alors quand un événement se produit, appelle ce foncteur.
    Voilà, c'est tout.

    T'as juste besoin d'une manière unifiée de pouvoir stocker les différents types de foncteurs, et c'est boost::function.

  5. #5
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut
    Bonjour loufoque,
    amdettons que j'ai un bouton, je veux lui connecter une fonction, une méthode ou plusieurs, tu ferais comment ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Bouton monBouton;
    monBouton.connect(/* un foncteur */);
    monBouton.connect(/* un autre foncteur */);
    Admettons que le premier foncteur est crée a partir d'un void toto() et le deuxieme d'un int tata(int);
    Comment je declare le signal dans mon bouton ?

    De plus admettons que j'ai deux methodes auxquelles je dois connecter des foncteurs differents, comme je peux faire ?
    Avec un connect qui prend en parametre le signal que auquel je veux connecter ?

    Ce que je veux faire est-il réalisable avec boost ?

    Merci.

  6. #6
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Un exemple de ce que l'on peut faire :

    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
    class Bouton
    {
    public :
     
        void OnClick(boost::function<void ()> F)
        {
            myOnClick = F;
        }
     
        void OnMouseMove(boost::function<void (int, int)> F)
        {
            myOnMouseMove = F;
        }
     
    private :
     
        void Update()
        {
            if (... detection du click souris ...)
                myOnClick();
     
            if (... detection du mouvement souris en (X, Y) ...)
                myOnMouseMove(X, Y);
        }
     
        boost::function<void ()> myOnClick;
        boost::function<void (int, int)> myOnMouseMove;
    };
     
    void OnMouseMove(int X, int Y)
    {
        std::cout << "Déplacement de la souris sur le bouton en " << X << ", " << Y << std::endl;
    }
     
    struct ClickHandler
    {
        void OnClick()
        {
            std::cout << "Click sur le bouton" << std::endl;
        }
    };
    ClickHandler Click;
     
    Bouton monBouton;
    monBouton.OnClick(boost::bind(&ClickHandler::OnClick, Click));
    monBouton.OnMouseMove(boost::bind(&OnMouseMove));
    [Code sorti à la volée sans vérification]

  7. #7
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut
    D'accord Laurent,
    mais comment je peux faire deux boutons, un qui appel une méthode qui prend pas de paramètre et un autre qui prend un paramètre ?
    Admettons par exemple que je veuille passer le bouton en paramètre du foncteur.
    Je suis obligé de créer une classe qui dérive de bouton ?

    Et maintenant je veux par exemple, un bouton qui appelle 2 foncteurs, le premier sans paramètre et le deuxième avec un paramètre.
    Est-ce que c'est possible ?

  8. #8
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    mais comment je peux faire deux boutons, un qui appel une méthode qui prend pas de paramètre et un autre qui prend un paramètre ?
    Si le paramètre est connu au moment où tu connectes le slot, tu peux le spécifier à boost::bind.
    Si tu parles de paramètres connus seulement au moment de l'évènement, alors tous les foncteurs connectés à cet évènement vont les recevoir (ie. ils auront le même type) non ?

    Et maintenant je veux par exemple, un bouton qui appelle 2 foncteurs, le premier sans paramètre et le deuxième avec un paramètre.
    Est-ce que c'est possible ?
    Plutôt que d'avoir un boost::function par évènement tu peux avoir un tableau. Ou connecter une fonction qui en appelle plusieurs autres.

  9. #9
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    mais comment je peux faire deux boutons, un qui appel une méthode qui prend pas de paramètre et un autre qui prend un paramètre ?
    Comme t'a montré Laurent.

    Admettons par exemple que je veuille passer le bouton en paramètre du foncteur.
    Je suis obligé de créer une classe qui dérive de bouton ?
    ???
    D'où tu sors cette idée farfelue ?

    Et maintenant je veux par exemple, un bouton qui appelle 2 foncteurs, le premier sans paramètre et le deuxième avec un paramètre.
    Est-ce que c'est possible ?
    Oui, comme t'a montré Laurent.

    Franchement, je comprends pas ton problème...

  10. #10
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par loufoque
    C'est simple, quand un évènement se produit tu veux appeler un foncteur. Alors quand un évènement se produit, appelle ce foncteur.
    Voilà, c'est tout.

    T'as juste besoin d'une manière unifiée de pouvoir stocker les différents types de foncteurs, et c'est boost::function.
    En gros, boost::signal, c'est ce que tu dis avec quelques détails supplémentaires, de tête :
    - La possibilité de gérer n foncteurs pour un signal (y compris en gérant la combinaison des valeurs de retour)
    - Une sorte de gestion automatique des durées de vie, qui efface les objets de connections quand un objet possédant un signal où un slot est détruit.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  11. #11
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut
    Je m'explique, je veux savoir si c'est possible de faire ceci avec une seule classe plutôt que 2.
    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
     
    class Bouton1
    {
        public:
          void onEvent(Event & event)
          {
             if(/* clic */)
               onClic();
          }
          void connect(boost::function<void ()>f)
          {
             onClic = f;
          }
     
        private:
          boost::function<void ()> onClic;
    };
     
    class Bouton2
    {
        public:
          void onEvent(Event & event)
          {
             if(/* clic */)
               onClic(event.x, event.y);
          }
          void connect(boost::function<void (int, int)>f)
          {
             onClic = f;
          }
     
        private:
          boost::function<void (int, int)> onClic;
    };
     
    void affiche(int x, int y)
    {
        std::cout << "Clic a la position : " << x << ',' << y << ".\n";
    }
     
    /* J'ai une instance app de Application qui a une methode quit() */
    Application app;
    Bouton1 bouton1;
    bouton1.connect(boost::bind(&Application::quit(), app);
     
    Bouton2 bouton2;
    bouton2.connect(boost::bind(&affiche);
    Citation Envoyé par Laurent Gomila
    Si le paramètre est connu au moment où tu connectes le slot, tu peux le spécifier à boost::bind.
    Ici, c'est comme si je faisais un bind1st ou bind2nd ?

  12. #12
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Je m'explique, je veux savoir si c'est possible de faire ceci avec une seule classe plutôt que 2
    Si j'ai bien compris tu voudrais que les paramètres (nombre et type) à passer au foncteur soient déterminés en fonction du type de celui-ci ?
    Je crois que là tu en demandes un peu trop
    En général les foncteurs liés à un même évènement ont tous le même type ; s'il se trouve que l'un d'entre eux n'a pas besoin d'un ou plusieurs des paramètres qui sont passés alors tant pis, il doit les déclarer quand même.

    Ici, c'est comme si je faisais un bind1st ou bind2nd ?
    Exactement. Sauf que boost::bind est beaucoup plus flexible / puissant.

  13. #13
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut
    Oui je voudrais passer n'importe quoi à mon bouton.
    Je voudrais avoir une list<boost::function> onClic; dans laquelle je peux mettre toutes sortes de foncteurs.

    Merci en tous cas pour vos réponses.

  14. #14
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Oui je voudrais passer n'importe quoi à mon bouton.
    Et si je lui connecte une fonction qui prend un std::string, trois Toto* et un tableau de float, il lui va lui passer quoi le bouton au moment où il va être cliqué ?

    Bref je ne comprend pas comment / pourquoi tu veux pouvoir connecter autre chose que des fonctions ayant un type bien défini qui correspond au type d'évènement.

  15. #15
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut
    D'accord il ne comprendra pas. Ça me paraissait bien sur le papier.
    C'est juste que si je veux passer une méthode avec 2 arguments et une sans arguments, je ne peux pas directement et je dois wrapper celle sans arguments.

  16. #16
    Membre émérite Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Par défaut
    Citation Envoyé par Laurent Gomila
    Et si je lui connecte une fonction qui prend un std::string, trois Toto* et un tableau de float, il lui va lui passer quoi le bouton au moment où il va être cliqué ?

    Bref je ne comprend pas comment / pourquoi tu veux pouvoir connecter autre chose que des fonctions ayant un type bien défini qui correspond au type d'évènement.
    Dans Qt, il était possible de connecter un signal qui émettait une variable, avec un slot qui ne prenait aucun argument, et donc de ne pas utiliser la variable émise.

  17. #17
    Membre Expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Par défaut
    Il y a un problème de logique plus profond... Lorsqu'un bouton est cliqué, il fait savoir qu'il est cliqué, ça ne nécessite pas d'argument, et en avoir serait "mauvais" à part éventuellement le bouton déclencheur. Si traitement il doit y avoir, c'est au niveau de ton foncteur que ça doit se faire.
    Et même les signaux/slots Qt fonctionne ainsi (avec une fonction renvoyant l'émetteur du message par contre).

  18. #18
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Citation Envoyé par HanLee
    Dans Qt, il était possible de connecter un signal qui émettait une variable, avec un slot qui ne prenait aucun argument, et donc de ne pas utiliser la variable émise.
    Il ne faut pas oublier que les slots / signaux de Qt sont passés dans une moulinette (MOC) avant d'être compilés. Je ne sais pas ce qu'il s'y passe exactement mais ça peut permettre plus de souplesse comparé à du code C++ standard.

  19. #19
    Membre émérite Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Par défaut
    Citation Envoyé par Laurent Gomila
    Il ne faut pas oublier que les slots / signaux de Qt sont passés dans une moulinette (MOC) avant d'être compilés. Je ne sais pas ce qu'il s'y passe exactement mais ça peut permettre plus de souplesse comparé à du code C++ standard.
    C'est sûr, d'ailleurs, il ne détecte pas les erreurs de typage (si l'on connecte un signal qui n'a pas la bonne signature), le tout passe silencieusement à la compilation...

    Mais c'était pour dire qu'on pourrait au moins proposer de relier soit à un callback avec arguments, soit sans arguments.

    Au lieu de surcharger connect(), on pourrait fabriquer un truc à l'aide de boost::variant.

  20. #20
    Membre Expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Par défaut
    Grosso modo, et pour rester dans les signaux/slots, il y est créé une fonction qui à partir d'une chaîne de caractères (le résultat des macros SIGNAL(...) et SLOT(...)) va appeller la fonction portant le même nom (c'est un switch bateau en somme ).

    Edit: c'était en réponse à Laurent à propos du rôle du moc.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Signaux et slots avec Qt4
    Par dourouc05 dans le forum Téléchargez
    Réponses: 0
    Dernier message: 01/11/2010, 22h23
  2. [Qt4] Signaux et Slot
    Par gentox dans le forum Qt
    Réponses: 9
    Dernier message: 25/01/2007, 18h35
  3. Réponses: 10
    Dernier message: 09/10/2005, 22h33

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