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

C++ Discussion :

[Conception] Implémentation d'un gestionnaire d'événements


Sujet :

C++

  1. #1
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut [Conception] Implémentation d'un gestionnaire d'événements
    Bonjour à tous,

    j'ai besoin d'implémenter un gestionnaire d'événements, et il y a plusieurs points qui me posent problème.

    D'abord, quelques specs:
    -> l'appli n'utilise qu'un seul thread, donc pas besoin de gérer le multi-thread
    -> un evenement tel que je le conçoit (peut-être que je me trompe ici) se définit par:
    . une classe cible
    . une fonction membre de cette classe cible
    . zéro, un ou deux paramètre(s) de type string et/ou int


    Voici une ébauche de mon gestionnaire d'événements tel que j'aimerais l'implémenter:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class EventManager
    {
    public:
    	int PushFront( Event evt ) // ajoute un evenmt en fin de liste
    	{eventList.push_front(evt);}
     
    	int PushBack( Event evt ); // ajoute un evenmt en debut de liste
    	{eventList.push_back(evt);}
     
    	void ExecuteEvents(); // execute sequentiellement tous les evenmts
     
    private:
    	std::list<Event> eventList;
    };
    En gros j'ai 2 ou 3 classes susceptibles d'exécuter des évéments.
    Un événement doit pouvoir être créé n'importe où dans le code (dans n'importe quelle classe) et ajouté au gestionnaire d'événement.

    Le but c'est qu'au final, le code de EventManager::ExecuteEvents() ressemble à ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    /*static*/ void ExecuteEvent(Event &event){event.Execute();}
    void EventManager::ExecuteEvents()
    {
        for_each( eventList.begin(), eventList.end(), ExecuteEvent );
    }
    Seulement voilà, je ne parviens pas à trouver une façon d'implémenter la classe Event pour pouvoir faire ça.

    Je n'ai pas réussi à trouver grand chose sur le net à ce sujet (et puis la connexion que j'ai en ce moment ne facilite pas la recherche...).

    Qu'en pensez-vous?
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  2. #2
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Tu aurais recours à boost ? (boost.signal, boost.bind, boost.function)
    Auquel cas tu fais ta liste, tu déclenches les signaux et tous les "callbacks" sont appelés.

    Il y a deux possibilités : soit tu considères un Event comme un boost.signal, soit tu le considères comme un pont entre un boost.signal lié à une instance de celui qui déclenche le signal et un callback lié à l'instance qui exécutera ce callback.

  3. #3
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Salut,
    je dirait que cette partie est mauvaise
    Citation Envoyé par r0d Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    /*static*/ void ExecuteEvent(Event &event){event.Execute();}
    void EventManager::ExecuteEvents()
    {
        for_each( eventList.begin(), eventList.end(), ExecuteEvent );
    }
    Je pense que un truc comme ExecuteNextEvent() appeler dans une boucle infinie est meilleur. Tu pourra ainsi ajouter des evenement plus important pendant l'execution. Et ce que tu as écrit je l'appellerai ExecuteAllEvent().

    Code C++ : 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
     
    class EventManager
    {
    public:
    	int PushFront( Event evt ,Priority) // ajoute un evenmt en fin de liste
     
    	int PushBack( Event evt ); // enlève un evenmt en debut de liste
     
    	void ExecuteNextEvents(); // execute l' evenement prioritaire  et l'enlève
           void ExecuteAllEvent();// execute tous les eveemnt  et les enlève
     
    private:
    	std::multimap<Event> eventList;
    };
    .
    .
    .
    int main()
    {
    EventManager myEventManager;
    ...
    while (1)
    {
    ...
    myEventManager.ExecuteNextEvents();
    ...
    }
    return 0;
    }
    }

  4. #4
    Membre éclairé Avatar de befalimpertinent
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    561
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Avril 2007
    Messages : 561
    Points : 833
    Points
    833
    Par défaut
    Un événement doit pouvoir être créé n'importe où dans le code (dans n'importe quelle classe) et ajouté au gestionnaire d'événement.
    Pour cela une bonne solution serait d'en faire un singleton.
    Linux > *

  5. #5
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Alp Voir le message
    Tu aurais recours à boost ? (boost.signal, boost.bind, boost.function)
    Auquel cas tu fais ta liste, tu déclenches les signaux et tous les "callbacks" sont appelés.

    Il y a deux possibilités : soit tu considères un Event comme un boost.signal, soit tu le considères comme un pont entre un boost.signal lié à une instance de celui qui déclenche le signal et un callback lié à l'instance qui exécutera ce callback.
    Ok, c'est une bonne idée, je vais voir ça.

    Citation Envoyé par Mongaulois Voir le message
    Salut,
    je dirait que cette partie est mauvaise

    Je pense que un truc comme ExecuteNextEvent() appeler dans une boucle infinie est meilleur. Tu pourra ainsi ajouter des evenement plus important pendant l'execution. Et ce que tu as écrit je l'appellerai ExecuteAllEvent().
    Mmhh. Ca me plait pas... En fait, je voudrais pouvoir exécuter ma pile d'événement a un instant donné, mais pas de façon continue. En je tiens à rester en single-thread. Tu vois ce que je veux dire?

    Citation Envoyé par befalimpertinent Voir le message
    Pour cela une bonne solution serait d'en faire un singleton.
    En effet, c'est ce que je comptais faire
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  6. #6
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par r0d Voir le message
    Mmhh. Ca me plait pas... En fait, je voudrais pouvoir exécuter ma pile d'événement a un instant donné, mais pas de façon continue. En je tiens à rester en single-thread. Tu vois ce que je veux dire?
    C'est pour cela que j'avais mis aussi void ExecuteAllEvent();
    Tu aura ainsi les deux methodes.

  7. #7
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Même si tu te fiche du MT, fait attention à ne pas avoir de la singletonite aigu.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  8. #8
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Bon, je suis parvenu à faire ce que je souhaitais grâce à boost.
    Voici mon code de test, pour ceux que ça intéresse:

    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
    #include <iostream>
    #include <list>
     
    #include <boost/function.hpp>
     
    // GPoint est une structure dont une instance va être passée en paramètre à
    // la fonction appelée par l'event
    struct GPoint
    {
    	GPoint(int px = 0, int py = 0) : x(px), y(py) {}
    	int x,y;
    };
     
    // Target1 et Target2 sont des classes qui contiennent une fonction (f1 et f2) qui sera appelée par l'event
    class Target1
    {
    public:
    	Target1(int a = 0) : _i (a) {}
     
    	// Add est la fonction qui va être appelée par l'event
    	void f1(GPoint pt)	{
    		_i = pt.x + pt.y;
    	}
     
    	void Print(){std::cout << "i = " << _i << std::endl;}
     
    private:
    	int _i;
    };
     
    class Target2
    {
    public:
    	Target2(int a = 0) : _i (a) {}
     
    	// Add est la fonction qui va être appelée par l'event
    	void f2(GPoint pt)	{
    		_i = pt.x - pt.y;
    	}
     
    	void Print(){std::cout << "i = " << _i << std::endl;}
     
    private:
    	int _i;
    };
     
    // classe abstraite IEvent (indispensable pour stocker les events dans un conteneur)
    class IEvent
    {
    public:
    	virtual void Execute() = 0;
    };
     
    // la classe event
    template <typename TargetObjType, typename ParamObjType>
    class GEvent : public IEvent
    {
    public:
    	// le constructeur
    	GEvent( TargetObjType* pTargetObj,
    		boost::function<void (TargetObjType*, ParamObjType)> targetFunc,
    		ParamObjType param):_targetObj(pTargetObj), _targetFunc(targetFunc),_param(param)
    	{}
     
    	// la fonction Execute
    	void Execute(){
    		_targetFunc( _targetObj, _param );
    	}
     
    private:
    	TargetObjType*	_targetObj;
    	boost::function<void (TargetObjType*, GPoint)>	_targetFunc;
    	ParamObjType	_param;
    };
     
    // un exemple d'utilisation
    int main(int argc, char* argv[])
    {
    	// création d'instances des classes cibles	
    	Target1* pTarget1 = new Target1();
    	Target2* pTarget2 = new Target2();
     
    	// affichage de l'état des classes cibles
    	pTarget1->Print();
    	pTarget2->Print();
     
    	// création de 2 evenements
    	GEvent<Target1, GPoint> *evt1 = new GEvent<Target1, GPoint>(pTarget1, &Target1::f1, GPoint(10,20) );
    	GEvent<Target2, GPoint> *evt2 = new GEvent<Target2, GPoint>(pTarget2, &Target2::f2, GPoint(1,2) );
     
    	// stockage des evenements dans une liste
    	std::list<IEvent*> l;
    	l.push_back( evt1 );
    	l.push_back( evt2 );
     
    	// execution des evenements
    	for ( std::list<IEvent*>::iterator it = l.begin();
    		it != l.end();
    		it++ )
    	{
    		(*it)->Execute();
    	}
     
    	// affichage de l'état des classes cibles
    	pTarget1->Print();
    	pTarget2->Print();
     
    	std::cin.get();
    	return 0;
    }
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Maj dynamique d'un gestionnaire d'événement
    Par Herode dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 31/03/2006, 10h15
  2. Gestionnaire d'évènements pour les fichiers sur disque
    Par chourmo dans le forum Composants VCL
    Réponses: 2
    Dernier message: 01/03/2006, 16h18
  3. Gestionnaire d'événements pour la souris en assembleur
    Par bassim dans le forum Assembleur
    Réponses: 2
    Dernier message: 09/12/2005, 23h45
  4. [VBA] Gestionnaire d'évènement commun
    Par Neilos dans le forum Access
    Réponses: 11
    Dernier message: 14/06/2005, 11h18
  5. Perte de gestionnaire d'événements dans une fenêtre
    Par Benjamin GAGNEUX dans le forum Composants VCL
    Réponses: 15
    Dernier message: 23/08/2004, 20h14

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