II. La gestion des évènements▲
Pour rendre notre application dynamique, il est possible (et heureusement) d'associer des méthodes à des évènements.
II-A. Principe de communication entre les objets▲
Chaque objet interactif possède un pointeur vers l'objet auquel il
doit envoyer ses messages. L'objet qui reçoit les messages connait les
associations messages / méthodes, il peut donc appeler les fonctions correspondantes
lorsqu'il reçoit des messages. Chaque type de message possède un identifiant ainsi
qu'une correspondance avec un évènement. Donc, quand un objet reçoit un message,
il en connait l'identifiant ainsi que l'évènement qui a généré le message.
La liste des associations entre messages et méthodes est définie par la macro
FXDEFMAP. Mais c'est au programmeur de renseigner cette macro de la manière
suivante :
FXDEFMAP(NotreWindow) NotreWindowMap[]={
//___Type du message________Identifiant________Méthode__________
FXMAPFUNC(SEL_COMMAND , NotreWindow::ID_NEW , NotreWindow::fct1),
FXMAPFUNC(SEL_MINIMIZE, NotreWindow::ID_END , NotreWindow::fct2),
FXMAPFUNC(SEL_COMMAND , NotreWindow::ID_FOX , NotreWindow::fct3),
FXMAPFUNC(SEL_MAXIMIZE, NotreWindow::ID_TOTO, NotreWindow::fct2),
[...]
FXMAPFUNC(SEL_MOTION , NotreWindow::ID_TATA, NotreWindow::fct4)
};Vous pouvez trouver la liste des types des messages ici.
Une fois la liste établie, il faut appeler la seconde macro qui permet d'implémenter notre liste d'associations
FXIMPLEMENT(NotreWindow,FXMainWindow,NotreWindowMap,ARRAYNUMBER(NotreWindowMap))Reste maintenant à informer la classe NotreWindow de l'existence de ces types de messages, en rajoutant un type enuméré en attribut de classe ainsi que les prototypes des fonctions associées.
class NotreWindow: public FXMainWindow{
FXDECLARE(NotreWindow);
private:
...
public:
...
enum{
ID_ZERO,
ID_NEW,
ID_END,
ID_FOX,
ID_TOTO,
ID_TATA
};
long fct1(FXObject*,FXSelector,void*);
long fct2(FXObject*,FXSelector,void*);
long fct3(FXObject*,FXSelector,void*);
long fct4(FXObject*,FXSelector,void*);
};Les fonctions à appeler lors d'un évènement ont toujours le prototype suivant :
long nom_fct(FXObject*,FXSelector,void*);où FXObject* est un pointeur sur l'objet qui a émis le message, FXSelector est le type du message et void* est un pointeur sur une structure représentant l'évènement qui a amené l'émission du message.
Vous en mourez d'envie, voici un petit exemple pour illustrer l'utilisation des évènements. Implémentons un label dont le texte change au clic sur un bouton.
#ifndef __NotreWindow_h__
#define __NotreWindow_h__
class NotreWindow : public FXMainWindow {
FXDECLARE(NotreWindow);
private:
NotreWindow(){}
FXLabel *lab;
FXButton *b1,*b2;
public:
NotreWindow(FXApp *);
void create();
enum{
ID_ZERO,
ID_CHANG,
ID_DEVEL
};
long onChangez(FXObject*,FXSelector,void*);
long onDeveloppez(FXObject*,FXSelector,void*);
};
#endif #include <fox/fx.h>
#include "NotreWindow.h"
FXDEFMAP(NotreWindow) NotreWindowMap[]={
FXMAPFUNC(SEL_COMMAND, NotreWindow::ID_CHANG , NotreWindow::onChangez),
FXMAPFUNC(SEL_COMMAND, NotreWindow::ID_DEVEL , NotreWindow::onDeveloppez)
};
FXIMPLEMENT(NotreWindow,FXMainWindow,NotreWindowMap,ARRAYNUMBER(NotreWindowMap))
NotreWindow::NotreWindow(FXApp *a):FXMainWindow(a,"Ma fenêtre FOX",NULL,NULL,DECOR_ALL,50,100,250,80){
int buttonStyle = FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_TOP|LAYOUT_LEFT;
lab=new FXLabel( this, "hello world",NULL,JUSTIFY_CENTER_X|LAYOUT_FILL_X );
b1 =new FXButton( this, "Changez" ,NULL,this,ID_CHANG,buttonStyle,0,0,0,0,10,10,5,5);
b2 =new FXButton( this, "Developpez" ,NULL,this,ID_DEVEL,buttonStyle,0,0,0,0,10,10,5,5);
}
void NotreWindow::create(){
FXMainWindow::create();
show(PLACEMENT_VISIBLE);
}
long NotreWindow::onDeveloppez(FXObject*,FXSelector,void*){
lab->setText("developpez");
return 0;
}
long NotreWindow::onChangez(FXObject*,FXSelector,void*){
lab->setText("changez");
return 0;
}II-B. Explications du code▲
J'ai déclaré deux pointeurs sur des boutons (FXButton), créés
dans le constructeur public de notre classe. On remarquera la présence
du premier argument this qui définit l'objet graphique contenant notre
bouton. Le second argument positionné à this correspond à un pointeur sur
l'objet à qui envoyer les messages, et dans notre cas, nous envoyons les
messages à la fenêtre. On remarquera aussi les arguments ID_CHANG et
ID_DEVEL décrivant le type des messages que les boutons émettront.
Comme la fenêtre sera amenée à recevoir des messages, elle doit connaître
les associations entre les messages et les fonctions à appeler, ceci est
fait via la macro FXDEFMAP
FXMAPFUNC(SEL_COMMAND, NotreWindow::ID_CHANG , NotreWindow::onChangez),
FXMAPFUNC(SEL_COMMAND, NotreWindow::ID_DEVEL , NotreWindow::onDeveloppez)Pour éviter les erreurs de résolution de symbole et les références indéfinies, il ne faut pas oublier de créer les méthodes onChangez et onDeveloppez :
long NotreWindow::onDeveloppez(FXObject*,FXSelector,void*){
lab->setText("developpez");
return 0;
}
long NotreWindow::onChangez(FXObject*,FXSelector,void*){
lab->setText("changez");
return 0;
}ainsi que les types de messages ID_CHANG et ID_DEVEL
class NotreWindow : public FXMainWindow {
...
public:
...
enum{
ID_ZERO,
ID_CHANG,
ID_DEVEL
};
...
};Attention à ne pas oublier de déclarer un premier item non utilisé pour le type énuméré. En effet, le premier item est géré comme étant 0, valeur ne convenant pas pour les message Fox. En ne déclarant pas le premier item, vous prenez le risque d'obtenir des comportements indéfinis.


