Vous êtes sur la page 1sur 25

Cours wxWidgets : 1re partie

Introduction
Vous vous apprtez suivre un tutoriel sur l'utilisation de la bibliothque wxWidgets (http://www.wxwidgets.org).
Il convient donc avant tout den faire une brve prsentation.
wxWidgets (au dpart, connue sous le nom wxWindows) est une bibliothque de dveloppement multi-plateforme.
Elle est disponible pour Windows, Linux, Mac, et bien d'autres systmes. Cela a l'avantage de rduire les temps de
programmation pour permettre une application de pouvoir tourner sur tous ces systmes d'exploitation.
Il est possible de l'utiliser en passant, bien sr, par le C++, mais galement Python, Perl, C#, ...
De plus, elle contient un grand nombre de classes simplifiant l'utilisation de certains contrles.
Pour ce qui est de l'interface graphique, wxWidgets utilise, pour chaque plateforme, les API natives. Ce qui fait
qu'une application aura, sous Windows, le look Windows, et sous Linux, le look Linux.
Pour plus d'informations sur ce point, je vous invite vous rendre sur le site officiel, o l'on peut trouver un bon
nombre de captures d'cran d'applications tournant sous plusieurs systmes d'exploitation.
Pour ce tutoriel, nous allons utiliser l'IDE Code::Blocks, qui d'ailleurs est bas sur wxWidgets, et qui de ce fait a
l'avantage d'tre disponible pour les principaux systmes d'exploitations (Windows, Linux, Mac).
Il vous faut donc l'installer, ainsi que les fichiers de dveloppement de wxWidgets.
Si le besoin sen fait sentir, jtofferai ce tutoriel afin dexpliquer la marche suivre pour ces installations, mais ce
nen nest pas le but premier, alors, nous verrons cela plus tard.

Quallons-nous faire au cours de cette premire partie ?


Comme il faut bien un but, nous allons raliser un petit utilitaire permettant de faire une recherche de fichiers.
Nous allons donc commencer par faire le minimum requis pour ce genre d'application : une simple recherche de
fichiers depuis un rpertoire donn, en utilisant des jockers (*.*, par exemple).
Puis, quand cette base sera fonctionnelle, nous tofferons un peu afin de lui ajouter quelques petites fonctionnalits
(recherche d'un mot l'intrieur des fichiers, options supplmentaires de recherche, ...).
Si vous avez des suggestions, n'hsitez pas m'en faire part.
Voici une capture, sous Windows et sous Ubuntu, de notre application telle qu'elle sera quand nous aurons termin
cette premire partie:

Chapitre 1 : la cration du projet


Cest parti !
Nous allons appeler notre utilitaire FileFinder (original, non ?).
Dmarrez Code::Blocks, crez un nouveau projet wxWidgets, donnez-lui le nom ci-dessus.
Pour les autres options du projet, voici ce qu'il faut mettre :
Preferred GUI Builder : None : nous allons coder l'interface la main... .
Application Type : Frame Based : notre fentre principale sera drive de la classe wxFrame.
wxWidget's Location : C'est vous qui voyez, en fonction de votre installation.
Nous n'aurons pas besoin d'une configuration debug, mais vous pouvez en crer une quand mme, si a vous
chante...
Crez un projet vide.
Pour les autres options, je vous laisse le choix (pour ma part, je choisis d'utiliser les Dll wxWidgets Unicode,
mais pas en monolithique, sans les Headers pr-compils ).
Nous sommes maintenant en possession d'un joli projet entirement vide.
Nous allons donc crer les deux classes principales de notre application :
La classe FileFinderApp, drive de wxApp. Chaque application wxWidgets classique doit possder une
classe drive de wxApp, et contenant au minimum une redfinition de la mthode OnInit(). Cette mthode
sera appele au lancement de l'application, et, en fonction de la valeur boolenne de retour, l'application
s'arrtera (valeur de retour = false) ou continuera (valeur de retour = true).
La classe MainFrame drive de wxFrame et qui sera la fentre principale de l'application.
Nous allons dans un premier temps nous occuper de la fentre.
Tout d'abord, crez un nouveau fichier vide (menu File New Empty file), rpondez Oui quand Code::Blocks
vous demande si vous voulez ajouter ce fichier au projet courant, et enregistrez-le en le nommant mainframe.h.
Rptez la mme opration pour un deuxime fichier que vous nommerez mainframe.cpp.
Ces deux fichiers doivent maintenant tre ouverts dans l'diteur de Code::Blocks.
Revenez sur le 1er fichier (mainframe.h) et entrez le code suivant (n'oubliez pas que le copier/coller est votre ami):
#ifndef MAINFRAME_H_INCLUDED
#define MAINFRAME_H_INCLUDED
// On ajoute les headers "basiques" de wxWidgets
#include <wx/wx.h>
// Dfinition de la classe "MainFrame"
class MainFrame : public wxFrame
{
public:
// Le constructeur
MainFrame();
// Le destructeur
~MainFrame();
};
#endif // MAINFRAME_H_INCLUDED

Il n'y a rien de particulier dire sur ce fichier. Passons maintenant au contenu du fichier mainframe.cpp :
// On rcupre la dfinition de la classe MainFrame
#include "mainframe.h"
// Le constructeur
MainFrame::MainFrame() : wxFrame(NULL,wxID_ANY,_T("FileFinder"))
{
// Nous ajouterons ici la cration des contrles que contiendra notre fentre
}
// Le Destructeur
MainFrame::~MainFrame()
{
// Nous ajouterons ici les ventuelles librations de mmoire ncessaires
// avant la fermeture de la fentre
}

Ici non plus, rien de particulier, si ce n'est l'appel au constructeur de wxFrame.


Il contient 3 paramtres :
NULL : correspond au pointeur vers la fentre parente (comme il s'agit de la fentre principale de notre
application, elle n'en a pas).
wxID_ANY : l'identifiant de notre fentre : dans notre cas, on laisse wxWidgets choisir la valeur. Nous
verrons plus tard que ce n'est pas toujours le cas.
_T("FileFinder') : il s'agit du texte qui apparatra dans la barre de titre de notre fentre. La macro wxT("...")
permet de ne pas avoir tenir compte du fait que notre application sera compile en Ansi ou en Unicode.
Nous allons maintenant nous occuper de la classe FileFinderApp, dont je vous ai parl un peu plus haut.
Crez d'abord les deux fichiers (vides) qui vont recevoir le code de cette classe : filefinderapp.h et
filefinderapp.cpp.
Pour le fichier filefinderapp.h, le code est :
#ifndef FILEFINDERAPP_H_INCLUDED
#define FILEFINDERAPP_H_INCLUDED
// On ajoute les headers "basiques" de wxWidgets
#include <wx/wx.h>
// Dfinition de la classe "FileFinderApp"
// Nous n'aurons pas besoin du constructeur et du destructeur
// Mais seulement de la mthode "Oninit()"
class FileFinderApp : public wxApp
{
public:
virtual bool OnInit();
};
DECLARE_APP(FileFinderApp);
#endif // FILEFINDERAPP_H_INCLUDED

Vous noterez l'ajout de la macro DECLARE_APP(FileFinderApp) qui permet wxWidgets de crer une fonction
wxGetApp(). Cette fonction nous permettra plus tard d'obtenir une rfrence vers notre classe d'application.
Elle n'est pas obligatoire, mais peut tre utile dans bien des cas.
Ensuite, le contenu du fichier filefinderapp.cpp :
// On rcupre la dfinition de la classe FileFinderApp
#include "filefinderapp.h"
// On rcupre la dfinition de la classe MainFrame
#include "mainframe.h"
// La mthode "OnInit()"
bool FileFinderApp::OnInit()
{
// On cre un objet "MainFrame"
MainFrame *frame=new MainFrame();
// On l'affiche
frame->Show();
// On indique que l'application peut continuer
return true;
}
IMPLEMENT_APP(FileFinderApp);

Encore une fois, je pense que le code est suffisamment comment. Il ne reste qu'une petite chose expliquer : la
macro IMPLEMENT_APP(FileFinderApp).
En fait, cette macro sert indiquer wxWidgets que la classe FileFinderApp est la classe principale de
l'application, et que c'est en fonction de la valeur de retour de sa mthode OnInit() qu'il faudra ou non continuer faire
tourner l'excutable.
Voil, nous avons la base de notre projet. Nous allons maintenant pouvoir compiler tout a, et l'excuter.

Normalement, si vous n'avez pas fait d'erreur lors de la recopie du code source, vous devriez obtenir une fentre
comme celle-ci :

J'en conviens, elle n'est pas trs belle, mais c'est dj un bon dbut.
Nous allons maintenant lui affecter une icne. Comme certains d'entre vous sont sous Linux, nous n'allons pas
utiliser un fichier ".ico", mais une image X-PixMap (http://fr.wikipedia.org/wiki/XPM).
Vous pouvez
tlcharger celle que nous allons utiliser l'aide du lien suivant :
http://x.psoud.free.fr/localfiles/articles/tutowxwidgets1/wxwidgets16x16.xpm . Enregistrez le fichier dans le rpertoire
du projet.
Pour utiliser un fichier XPM tel que celui-ci, il suffit de l'inclure dans la code source avec la directive #include.
Ensuite, dans le constructeur de la fentre, nous allons affecter cette icne la fentre avec la mthode
SetIcon(......). Notre fichier mainframe.cpp devient donc :
// On rcupre la dfinition de la classe MainFrame
#include "mainframe.h"
// On ajoute le fichier XPM de l'icne
#include "wxwidgets16x16.xpm"
// Le constructeur
MainFrame::MainFrame() : wxFrame(NULL,wxID_ANY,_T("FileFinder"))
{
// On affecte l'icne la fentre
SetIcon(wxwidgets16x16_xpm);
// Nous ajouterons ici la cration des contrles que contiendra notre fentre
}
// Le Destructeur
MainFrame::~MainFrame()
{
// Nous ajouterons ici les ventuelles librations de mmoire ncessaires
// avant la fermeture de la fentre
}

Voil, c'est tout : vous pouvez compiler et excuter, vous devriez obtenir la mme fentre que prcdemment, mais
avec une icne personnalise :

Chapitre 2 : La mise en place des contrles


Maintenant que nous possdons une fentre, nous allons pouvoir y ajouter des contrles, afin de la rendre un peu
plus utile.
Pour cela, nous allons avoir besoin d'une partie un peu obscure de wxWidgets pour qui n'y est pas habitu : les
wxSizer, et leurs classes drives.
Mais tout d'abord, qu'est-ce qu'un sizer ?
Il s'agit en fait d'un contrle "virtuel" servant la mise en place et au redimensionnement automatique des autres
contrles.
Par exemple, sans utiliser les sizers, si je veux placer sur ma fentre un label (un wxStaticText]), et sur la mme
ligne, une zone de texte (un wxTextCtrl) qui occupera le reste de la fentre en largeur, avec un espace de 5 pixels entre
les deux, il va falloir que je procde de la faon suivante :
Rcuprer la largeur de la fentre (de sa zone cliente, en fait).
Crer le contrle wxStaticText la position x0/y0.
Mesurer sa largeur et y ajouter 5 pixels pour obtenir la position du contrle suivant.
Crer le contrle wxTextCtrl la bonne position, et de la bonne taille.
Intercepter l'vnement "OnSize" de la fentre.
Refaire les calculs et repositionner les contrles chaque redimensionnement de la fentre.
Avec les sizers, tout cela se fait automatiquement :
On cre le sizer en lui indiquant dans quel sens il faudra qu'il intervienne sur les contrles (horizontal ou
vertical). Ainsi, pour lexemple ci-dessus, il sagirait dun sizer horizontal.
Crer le wxStaticText sans se soucier de sa taille et de sa position), et lajouter au sizer en lui indiquant que ce
contrle a une taille fixe, et qu'il ne doit pas tre redimensionn.
Crer le wxTextCtrl et lajouter au sizer en indiquant qu'il doit tre redimensionn pour occuper le reste de la
largeur de la fentre.
Il est galement possible de donner une valeur aux marges laisser autour de chaque contrle
Il suffit d'affecter le sizer la fentre, et c'est lui qui va se charger de grer le redimensionnement.
Et si l'on a plusieurs lignes grer, il suffit de crer plusieurs sizers horizontaux, et de les ajouter un sizer vertical.
De plus, il existe plusieurs sortes de sizers qui permettent d'obtenir des rsultats diffrents :
wxBoxSizer : c'est le sizer classique (en fait, la classe wxSizer n'est pas utilisable telle-quelle, elle sert
uniquement de base aux autres). Ce sizer cre en quelque sorte une boite virtuelle dans laquelle seront
placs et organiss les contrles en fonctions des paramtres passs lors de leur ajout. C'est le premier sizer
que nous utiliserons, pour mettre en place correctement les parties gauche (critres de recherche) et droite
(rsultats de la recherche) de notre interface
wxStaticBoxSizer : ce sizer a un comportement identique au prcdent, mais il est associ un contrle
cadre (wxStaticBox). C'est ce sizer que nous utiliserons pour organiser les contrles l'intrieur des deux
zones (gauche et droite) de notre interface.
wxGridSizer : comme son nom l'indique, il permet d'organiser les contrles sur une grille virtuelle, dont les
cases auront toutes la mme taille.
wxFlexGridSizer : comme le prcdent, il va organiser les contrles sur une grille, mais en offrant la
possibilit d'avoir des lignes et des colonnes de taille diffrentes.
wxGridBagSizer : il s'agit d'un wxFlexGridSizer offrant la possibilit de placer un contrle cheval sur
plusieurs cellules, ou une position donne (par exemple, dans la 3me cellule de la 2me ligne, mme si les
cellules prcdentes ne sont pas encore affectes).
Comme je viens de vous le dire, nous n'utiliserons que les deux premiers types de sizer. Nous allons maintenant en
voir le fonctionnement.

Le wxBoxSizer
Lors de sa construction, on lui donne en paramtre la direction dans laquelle ce sizer doit agir. Deux constantes
wxWidgets sont disponibles pour cela : wxHORIZONTAL et wxVERTICAL (je suppose que vous avez devin leur
signification).
Donc, si on veut crer un wxBoxSizer horizontal, il suffit d'crire :
wxBoxSizer *hsizer=new wxBoxSizer(wxHORIZONTAL);

Pour lui ajouter un contrle, il suffit d'utiliser sa mthode Add(...).

Nous lui passerons en premier paramtre un pointeur vers le contrle (ou vers un autre sizer) grer.
Le deuxime paramtre concerne la proportion que le sizer doit donner au contrle : une valeur 0 indique que le
contrle ne doit pas tre redimensionn, sinon, il suffit de mettre une valeur entire. Par exemple, si on ajoute un
bouton avec la proportion 1 , et une zone de texte avec la proportion 4 , la zone de texte aura 4 fois la taille du
bouton.
Viens ensuite un paramtre flag , qui est directement associ au 4me paramtre : la valeur des marges. Ce 3me
paramtre est une combinaison des valeurs suivantes :
wxALL : la valeur des marges est appliquer sur les 4 bords du contrle.
wxLEFT, wxRIGHT, wxTOP, wxBOTTOM : pour n'appliquer la valeur des marges que sur un ou plusieurs
bords. Il faut en effet garder l'esprit que si l'on ajoute un premier contrle avec une marge de 5 pixels tout
autour, puis un deuxime contrle avec la mme marge, il y aura un espace de 10 pixels entre les deux. Dans
ce cas, il suffit de n'appliquer la marge que sur les bords "haut","bas","droite" du deuxime contrle pour
respecter les 5 pixels.
wxEXPAND : le contrle sera tendu dans la direction complmentaire celle du sizer, pour en occuper tout
l'espace. Par exemple, avec un sizer horizontal, si l'on insre une zone de texte multi-lignes, puis un simple
bouton, le bouton sera forcment moins haut que la zone de texte. Le flag wxEXPAND va tendre le
bouton pour qu'il occupe toute la hauteur.
Pour les autres valeurs que peut prendre ce paramtre, je vous laisse consulter la documentation officielle
concernant les sizers : http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html (en anglais).

Le wxStaticBoxSizer
Son fonctionnement est identique celui du wxBoxSizer que l'on vient de voir, mais il permet d'afficher en plus une
wxStaticBox, c'est dire, un cadre avec une lgende en haut gauche.
Il suffit de lui ajouter un pointeur vers le contrle parent de la wxStaticBox, et un wxString contenant le texte de
lgende afficher, et le tour est jou :
wxStaticBoxSizer *hsizer=new wxStaticBoxSizer(wxHORIZONTAL, maFrame, _T("Texte afficher :"));

Voil pour ce qui est des explications de base sur les sizers. Nous allons maintenant voir comment nous allons les
utiliser pour notre interface.
Il va d'abord falloir que l'on gre les deux zones gauche et droite . Nous allons donc crer un premier
wxBoxSizer horizontal.
Pour chacune de ces zones, nous utiliserons un wxStaticBoxSizer :
pour la partie de gauche, ce sizer va devoir grer plusieurs lignes de contrles; il sera donc vertical. Ensuite,
pour chaque ligne, il faudra ensuite ajouter un wxBoxSizer horizontal ds qu'il y aura plus d'un contrle sur la
ligne concerne.
pour la partie de droite, le sizer n'ayant qu'un seul contrle grer (la liste des rsultats), il pourra tre
indiffremment horizontal ou vertical.
Nous allons maintenant dresser la liste des contrles dont nous aurons besoin, afin de dterminer quelles variables
nous allons devoir crer pour leur utilisation:
Commenons par la zone de gauche :
Nous n'aurons pas besoin de modifier le texte de la wxStaticBox principale. Il est donc inutile de crer une
variable pour cela.
De mme pour le label Nom du (des) fichier(s) : (un wxStaticText).
Par contre, pour la zone de texte servant recevoir le nom ou les jockers de recherche (un wxTextCtrl), nous
allons avoir besoin d'un pointeur qui nous permettra d'en rcuprer la valeur.
Le label Rechercher dans : est log la mme enseigne que le prcdent : nous n'aurons pas besoin de le
modifier.
Nous aurons besoin d'un pointeur vers la zone de texte servant la saisie du dossier de dmarrage, pour en
rcuprer le contenu, ou pour le modifier.
Nous aurons galement besoin d'un identifiant pour le bouton parcourir situ droite de cette dernire
zone de texte, ainsi que d'un pointeur nous permettant de l'activer ou de le dsactiver. Cet identifiant est en fait
une valeur entire unique (que nous demanderons wxWidgets de crer pour nous) et qui, comme son nom le
laisse supposer, sert identifier un contrle, et le connecter la table des vnements (nous verrons cela plus
loin, rassurez-vous).
Comme pour le bouton prcdent, il nous faudra un identifiant et un pointeur pour le bouton Dmarrer .

Pour la zone de droite :


Il serait souhaitable de garder un pointeur vers la wxStaticBox principale, pour pouvoir afficher le nombre de
rsultats trouvs.
Il nous faut galement un pointeur pour le contrle wxListCtrl servant l'affichage des rsultats.
Nous allons, dans un premier temps, ajouter les variables et les consantes (pour les identifiants des boutons) notre
classe MainFrame (fichier mainframe.h):
#ifndef MAINFRAME_H_INCLUDED
#define MAINFRAME_H_INCLUDED
// On ajoute les headers "basiques" de wxWidgets
#include <wx/wx.h>
// On ajoute le header du contrle wxListCtrl, qui n'est pas inclus
// Dans les headers "basiques"
#include <wx/listctrl.h>
// Dfinition de la classe "MainFrame"
class MainFrame : public wxFrame
{
public:
// Le constructeur
MainFrame();
// Le destructeur
~MainFrame();
private:
// Les pointeurs vers les wxTextCtrl pour le nom/les jockers et le dossier de dmarrage
wxTextCtrl *txtName, *txtPath;
// Les pointeur vers les boutons "Parcourir" et "Dmarrer"
wxButton *btnBrowse, *btnStart;
// Les identifiants pour ces mme boutons
static const int ID_BTN_BRWSE,ID_BTN_START;
// Le pointeur vers la wxStaticBox de droite pour l'affichage du nombre de rsultats trouvs
wxStaticBox *stbNumRes;
// Le pointeur vers le wxListCtrl pour l'affichage des rsultats.
wxListCtrl *lstResults;
};
#endif // MAINFRAME_H_INCLUDED

Vous remarquerez, au passage, qu'il a fallu inclure un header spcifique pour le wxListCtrl, car il ne fait pas partie
des contrles de base de wxWidgets.
Nous allons passer la cration des contrles. Tout se fait dans le constructeur de la fentre principale.
Il va galement falloir que l'on ajoute la dfinition des deux constantes relatives aux boutons (les identifiants).
Comme je vous l'ai dit prcdemment, ces constantes doivent avoir une valeur unique. En effet, si deux boutons ont le
mme identifiant, on ne pourra pas savoir sur lequel l'utilisateur a cliqu.
Pour cette valeur unique, il est possible d'utiliser des valeurs prdfinies par wxWidgets
(http://www.wxwidgets.org/manuals/stable/wx_eventhandlingoverview.html#windowids ) pour les actions les plus
courantes telles que ouvir , fermer , aide ,....... Nous pouvons galement dfinir ces valeurs nous mme, en
prenant garde de ne pas utiliser une valeur prsente dans la liste dont je viens de vous donner le lien. La dernire
possibilit est de demander wxWidgets de nous crer une nouvelle valeur unique, par l'intermdiaire de la fonction
wxNewId().
Voici donc ce qu'il suffira de mettre avant le constructeur de la fentre principale :
// On affecte les identifants des deux boutons
const int MainFrame::ID_BTN_BRWSE = wxNewId();
const int MainFrame::ID_BTN_START = wxNewId();

Maintenant, avant la cration des contrles, il nous reste un petit dtail rgler. Je ne sais pas si vous avez
remarqu, mais le fond de la fentre est d'une couleur lamentable. Nous allons remdier cela en modifiant cette
couleur. Nous allons lui affecter une couleur systme qui est la couleur par dfaut pour la face des boutons , et
dont nous pouvons rcuprer la valeur grce wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE) :
// On change la couleur du fond de la fentre
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));

On peut maintenant dmarrer la cration des contrles. En premier lieu, le wxBoxSizer principal (il est horizontal, et
va recevoir les deux zones "gauche" et "droite").
// On cre d'abord, le wxBoxSizer principal
wxBoxSizer *mainsizer=new wxBoxSizer(wxHORIZONTAL);

Ensuite, vient le premier wxStaticBoxSizer (vertical) qui va contenir les contrles pour les critres de recherche :
// On cre maintenant le wxStaticBoxSizer pour la partie de gauche
wxStaticBoxSizer *left_vsizer=new wxStaticBoxSizer( wxVERTICAL, this,
_T("Critres de recherche :"));

Puis le premier contrle de la partie de gauche : un wxStaticText. Normalement, lors de la cration de contrles
avec wxWidgets, il faut donner un identifiant chaque fois. Cela peut vite devenir pnible, d'autant plus que lon nen
a pas tout le temps besoin, comme maintenant.
Il existe pour cela un identifiant passe partout dont la constante est wxID_ANY (et dont la valeur est -1) pour
indiquer wxWidgets de se dbrouiller tout seul :
// On cre le premier wxStaticText
wxStaticText *label=new wxStaticText(this,wxID_ANY,_T("Nom du(des) fichier(s) :"));

Et on l'ajoute au sizer vertical. Comme ce contrle n'a pas besoin d'tre redimensionn, on lui met la proportion 0 .
On va mettre une marge de 5 pixels partout, sauf en dessous (il sera coll au contrle suivant). Ce qui donne :
// On l'ajoute au wxStaticBoxSizer
left_vsizer->Add(label,0,wxLEFT|wxRIGHT|wxTOP,5);

Maintenant, c'est au tour du premier wxTextCtrl, dont on a dclar le pointeur comme variable membre prive de la
classe MainFrame (son nom est txtName) :
// On cre ensuite le premier wxTextCtrl :
txtName=new wxTextCtrl(this,wxID_ANY,_T("*.*"));

Et on l'ajoute au sizer, sachant que cette fois-ci, il devra tre tendu pour tenir sur toute la largeur (flag
wxEXPAND), avoir une marge gauche, droite, et en bas (pas en haut, pour tre coll au contrle prcdent), et ne
pas tre redimensionn en hauteur (proportion 0 ) :
// On l'ajoute au sizer
left_vsizer->Add(txtName,0,wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND,5);

On rpte l'opration pour le deuxime wxStaticText, sachant que l'on peut rutiliser la variable du premier, qu'il ne
faut pas lui mettre de marge suprieure, car le contrle prcdent en a dj une infrieure :
// On cre le deuxime wxStaticText
label=new wxStaticText(this,wxID_ANY,_T("Rechercher dans :"));
// On l'ajoute au sizer
left_vsizer->Add(label,0,wxLEFT|wxRIGHT,5);

Bien, maintenant, on va corser un peu tout a. En effet, pour la ligne suivante, nous allons devoir ajouter un
wxBoxSizer horizontal, pour placer sur la mme ligne un wxTextCtrl et un wxButton :
// Le wxBoxSizer horizontal pour la 2me zone de texte et le bouton "Parcourir"
wxBoxSizer *h_sizer1=new wxBoxSizer(wxHORIZONTAL);

Maintenant, on peut crer le wxTextCtrl et l'ajouter ce dernier sizer (pas de marge car on en mettra une au sizer
plus tard, proportion = 1 car redimensionnable dans le sens du sizer) :
// La deuxime zone de texte
txtPath=new wxTextCtrl(this,wxID_ANY,_T(""));
// On l'ajoute au sizer horizontal
h_sizer1->Add(txtPath,1,wxALL,0);

On fait de mme pour le bouton. La diffrence avec le contrle prcdent est que nous allons lui affecter
l'identifiant cr plus haut (ID_BTN_BRWSE), et que nous allons lui spcifier une largeur fixe. En effet, si on ne met
rien pour la taille du contrle, wxWidgets va utiliser une taille standard, qui sera trop large pour un bouton comme le
ntre (jetez un coup dil aux premires captures dcran pour vous en rendre compte).
Pour pouvoir accder au paramtre taille , il faut d'abord que l'on fournisse le paramtre position . Or, c'est le
sizer qui va dcider de la position du bouton. Nous allons juste lui passer une macro : wxDefaultPosition. Cette macro
veut en fait dire : wxPoint(-1,-1), c'est--dire, une valeur wxPoint(x,y) dont on ne spcifie pas les coordonns.
Ensuite, pour le paramtre taille , nous allons utiliser une valeur wxSize(largeur, hauteur). Comme nous ne
sommes intresss que par la largeur, nous mettrons la hauteur -1 pour utiliser la valeur par dfaut du systme.
Notre bouton ne devra tre redimensionnable dans aucune direction (proportion 0 , et pas de flag wxEXPAND),
et nous allons lui donner une marge gauche, pour qu'il ne soit pas coll au wxTextCtrl prcdent :
// Le bouton "Parcourir"
btnBrowse=new wxButton(this,ID_BTN_BRWSE,_T(". . ."),wxDefaultPosition,wxSize(30,-1));
// On l'ajoute au sizer horizontal
h_sizer1->Add(btnBrowse,0,wxLEFT,5);

Voil, notre sizer horizontal est prt. Nous pouvons l'ajouter au sizer vertical comme un contrle normal. Il sera
non redimensionnable verticalement (proportion "0"), extensible horizontalement (flag wxEXPAND), et n'aura pas de
marges suprieure pour tre coll au wxStaticText:
// On ajoute le sizer horizontal au sizer vertical
left_vsizer->Add(h_sizer1,0,wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND,5);

Il nous reste maintenant crer le bouton "Dmarrer", et l'ajouter au sizer vertical, en lui donnant le flag
wxALIGN_RIGHT pour qu'il soit plac droite de la zone (a fait plus joli, je trouve):
// Le bouton "Dmarrer"
btnStart=new wxButton(this,ID_BTN_START,_T("Dmarrer"));
// On l'ajoute au sizer vertical
left_vsizer->Add(btnStart,0,wxALL|wxALIGN_RIGHT,5);

Nous avons mainenant termin la cration des contrles de la partie gauche.


Il faut encore que l'on ajoute le wxStaticBoxSizer (vertical) au wxBoxSizer principal (horizontal) :
// On ajoute le premier wxStaticBoxSizer au wxBoxSizer principal
mainsizer->Add(left_vsizer,0,wxALL|wxEXPAND,5);

Nous allons maintenant nous occuper de la partie droite.


Le dbut est le mme que pour la partie de gauche (cration du wxStaticBoxSizer vertical), mais il faut en plus que
l'on rcupre le pointeur vers la wxStaticBox qu'il cre, pour pouvoir en changer le texte plus tard.
Autre petite chose : il faut que l'on donne une largeur minimale ce sizer (300 pixels), pour que le wxListCtrl que
nous allons lui ajouter ensuite soit de taille correcte :
// On cre le deuxime wxStaticBoxSizer
wxStaticBoxSizer *right_vsizer=new wxStaticBoxSizer(wxVERTICAL,this,
_T("Rsultats de la recherche :"));
// On rcupre le pointeur vers la wxStaticBox
stbNumRes=right_vsizer->GetStaticBox();
// On dfini la largeur minimale pour le deuxime wxStaticBoxSizer
right_vsizer->SetMinSize(300,-1);

Maintenant, on va s'occuper du dernier contrle: le wxListCtrl.


Pour l'affichage de la liste des rsultats, on va lui donner le style wxLC_REPORT , qui correspond la vue
dtails des gestionnaires de fichiers.
Le paramtre style se trouvant aprs la position et la taille, nous allons utiliser les macros
wxDefaultPosition et wxDefaultSize .
Nous allons ensuite lui crer 3 colonnes : une pour le nom du fichier/dossier, une pour le type (fichier ou dossier) et
une pour l'emplacement.
Nous utiliserons pour cela la mthode wxListCtrl::InsertColumn(), avec comme paramtres : le numro de la
colonne, le texte de l'en-tte, l'alignement et la largeur.

Nous l'ajouterons ensuite au deuxime sizer vertical, avec une marge de 5 pixels tout autour, une proportion de
1 car il devra occuper toute la hauteur de la zone, et le flag wxEXPAND pour qu'il en occupe toute la largeur.
Ce qui nous donne :
// On cre le wxListCtrl
lstResults=new wxListCtrl(this,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxLC_REPORT);
// On ajoute les colonnes
lstResults->InsertColumn(0,_T("Nom"),wxLIST_FORMAT_LEFT);
lstResults->InsertColumn(1,_T("Type"),wxLIST_FORMAT_CENTER);
lstResults->InsertColumn(2,_T("Emplacement"),wxLIST_FORMAT_LEFT);
// On ajoute le wxListCtrl au wxStaticBoxSizer
right_vsizer->Add(lstResults,1,wxALL|wxEXPAND,5);

La zone de droite est maintenant termine. On peut ajouter le sizer vertical au sizer principal :
// On ajoute le deuxime sizer vertical au sizer principal
mainsizer->Add(right_vsizer,1,wxTOP|wxBOTTOM|wxRIGHT|wxEXPAND,5);

Il reste maintenant affecter le sizer principal la fentre :


// On affecte le wxBoxSizer principal la fentre
SetSizer(mainsizer);

On demande le calcul de la taille minimale de la fentre en fonction de celle des contrles :


// On calcule la taille minimale de la fentre
mainsizer->SetSizeHints(this);

Voil, c'est termin. Notre interface est prte. Vous pouvez compiler et excuter, pour voir ce que a donne :

Voici un rcapitulatif du fichier mainframe.cpp :


// On rcupre la dfinition de la classe MainFrame
#include "mainframe.h"
// On ajoute le fichier XPM de l'icne
#include "wxwidgets16x16.xpm"
// On affecte les identifants des deux boutons
const int MainFrame::ID_BTN_BRWSE = wxNewId();
const int MainFrame::ID_BTN_START = wxNewId();

// Le constructeur
MainFrame::MainFrame() : wxFrame(NULL,wxID_ANY,_T("FileFinder"))
{
// On affecte l'icne la fentre
SetIcon(wxwidgets16x16_xpm);
// On change la couleur du fond de la fentre
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
// On cre d'abord, le wxBoxSizer principal
wxBoxSizer *mainsizer=new wxBoxSizer(wxHORIZONTAL);
// On cre maintenant le wxStaticBoxSizer pour la partie de gauche
wxStaticBoxSizer *left_vsizer=new wxStaticBoxSizer(wxVERTICAL,this,
_T("Critres de recherche :"));
// On cre le premier wxStaticText
wxStaticText *label=new wxStaticText(this,wxID_ANY,_T("Nom du(des) fichier(s) :"));
// On l'ajoute au wxStaticBoxSizer
left_vsizer->Add(label,0,wxLEFT|wxRIGHT|wxTOP,5);
// On cre ensuite le premier wxTextCtrl :
txtName=new wxTextCtrl(this,wxID_ANY,_T("*.*"));
// On l'ajoute au sizer
left_vsizer->Add(txtName,0,wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND,5);
// On cre le deuxime wxStaticText
label=new wxStaticText(this,wxID_ANY,_T("Rechercher dans :"));
// On l'ajoute au sizer
left_vsizer->Add(label,0,wxLEFT|wxRIGHT,5);
// Le wxBoxSizer horizontal pour la 2me zone de texte et le bouton "Parcourir"
wxBoxSizer *h_sizer1=new wxBoxSizer(wxHORIZONTAL);
// La deuxime zone de texte
txtPath=new wxTextCtrl(this,wxID_ANY,_T(""));
// On l'ajoute au sizer horizontal
h_sizer1->Add(txtPath,1,wxALL,0);
// Le bouton "Parcourir"
btnBrowse=new wxButton(this,ID_BTN_BRWSE,_T(". . ."),
wxDefaultPosition,wxSize(30,-1));
// On l'ajoute au sizer horizontal
h_sizer1->Add(btnBrowse,0,wxLEFT,5);
// On ajoute le sizer horizontal au sizer vertical
left_vsizer->Add(h_sizer1,0,wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND,5);
// Le bouton "Dmarrer"
btnStart=new wxButton(this,ID_BTN_START,_T("Dmarrer"));
// On l'ajoute au sizer vertical
left_vsizer->Add(btnStart,0,wxALL|wxALIGN_RIGHT,5);
// On ajoute le premier wxStaticBoxSizer au wxBoxSizer principal
mainsizer->Add(left_vsizer,0,wxALL|wxEXPAND,5);
// On cre le deuxime wxStaticBoxSizer
wxStaticBoxSizer *right_vsizer=new wxStaticBoxSizer(wxVERTICAL,this,
_T("Rsultats de la recherche :"));
// On rcupre le pointeur vers la wxStaticBox
stbNumRes=right_vsizer->GetStaticBox();
// On dfini la largeur minimale pour le deuxime wxStaticBoxSizer
right_vsizer->SetMinSize(300,-1);
// On cre le wxListCtrl
lstResults=new wxListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxLC_REPORT);
// On ajoute les colonnes
lstResults->InsertColumn(0,_T("Nom"),wxLIST_FORMAT_LEFT);
lstResults->InsertColumn(1,_T("Type"),wxLIST_FORMAT_CENTER);
lstResults->InsertColumn(2,_T("Emplacement"),wxLIST_FORMAT_LEFT);
// On ajoute le wxListCtrl au wxStaticBoxSizer
right_vsizer->Add(lstResults,1,wxALL|wxEXPAND,5);
// On ajoute le deuxime sizer vertical au sizer principal
mainsizer->Add(right_vsizer,1,wxTOP|wxBOTTOM|wxRIGHT|wxEXPAND,5);
// On affecte le wxBoxSizer principal la fentre
SetSizer(mainsizer);
// On calcule la taille minimale de la fentre
mainsizer->SetSizeHints(this);
// Et voil, c'est termin
}

// Le Destructeur
MainFrame::~MainFrame()
{
// Nous ajouterons ici les ventuelles librations de mmoire ncessaires
// avant la fermeture de la fentre
}

Allez, puisque vous avez t trs attentifs, je vais vous donner un petit bonus (enfin, aux utilisateurs de Windows).
Vous avez sans-doute remarqu deux choses :
Premirement, l'excutable qui a t gnr ne possde pas d'icne.
Deuximement, les contrles ne prennent pas en compte le thme de Windows.
Nous allons remdier cela par l'intermdiaire d'un fichier ressources .
En effet, sous Windows, il est possible d'ajouter de nombreuses donnes dans l'excutable (images, sons, ...).
Pour cela, nous allons d'abord crer le fichier ressources.
Sous Code::Blocks, crez un nouveau fichier vide (menu File New Empty file), rpondez Oui lorsqu'on
vous demande si vous voulez ajouter ce fichier au projet courant, et enregistrez-le sous le nom resources.rc .
Nous allons tout d'abord ajouter l'icne de l'excutable. Vous pouvez utiliser n'importe quel fichier .ico valide.
De mon ct, je vais utiliser le fichier icne standard wxWidgets. Il se trouve normalement dans l'arborescence
de votre installation des libs wxWidgets, dans le dossier include\wx\msw et se nomme std.ico .
Nous allons donc indiquer au compilateur qu'il doit l'intgrer l'excutable.
Dans le fichier resources.rc que vous venez de crer, ajouter la ligne :
appIcon ICON "wx/msw/std.ico"

A noter que le nom appIcon n'a pas t donn au hasard. Windows classe les icnes par ordre alphabtique, et
prend le premier pour l'affichage dans l'explorateur. Avec un tel nom, il y a de fortes chances que l'icne std.ico
soit place en tte de liste, et soit utilise pour reprsenter lexcutable dans lexplorateur Windows.
Nous allons galement intgrer le fichier Manifest cet excutable, pour que les contrles aient le look Windows.
Ce fichier manifest se trouve normalement au mme endroit que l'icne utilise prcdemment.
Ajoutez la ligne suivante au fichier resources.rc :
1 24 "wx/msw/wx.manifest"

Le 1 correspond l'identifiant du Manifest , et le 24 son type. Ces deux valeurs doivent toujours tre
celles-ci pour un fichier manifest.
Vous pouvez maintenant compiler. Votre fichier FileFinder.exe doit maintenant tre dot d'une icne identique
celle que nous avons affecte la fentre. De plus, si vous excutez une dernire fois l'application, les contrles ont
maintenant le look Windows (enfin, pour ceux qui sont sous Windows XP ou Vista).

Chapitre 3 : La mise en place des mthodes vnementielles


Nous avons cr une belle fentre, mais elle ne fait pour l'instant pas grand chose.
Il faut que l'on indique notre application de ragir en fonction des actions de l'utilisateur:
Lorsqu'il clique sur le bouton Parcourir , il faut ouvrir une boite de dialogue de slection de rpertoire pour
lui permettre de slectionner le dossier dans lequel va dbuter la recherche.
Lorsqu'il clique sur le bouton Dmarrer , il faut mettre en route la recherche des fichiers avec les critres
qu'il a fourni.
Nous allons donc dans un premier temps modifier notre classe MainFrame pour lui ajouter les mthodes qui vont
tre appeles lors des clics sur les boutons Parcourir et Dmarrer .
Ensuite, nous allons connecter ces mthodes la table des vnements, de faon indiquer l'OS o se trouve le
code excuter lorsque l'utilisateur clique sur un bouton. Comme nous avons deux vnements grer, nous allons
pouvoir mettre en place deux mthodes diffrentes pour cette connexion
Nous allons donc ajouter deux mthodes la classe MainFrame.
La premire, que nous appellerons OnButtonBrowseClicked sera appele chaque fois que l'utilisateur cliquera
sur le bouton Parcourir .
La deuxime, que nous appellerons OnButtonStartClicked sera appele lors du clic sur le bouton Dmarrer
Nous ne nous occuperons pas pour l'instant du contenu de ces mthodes. Nous y placerons simplement un appel
la fonction wxMessageBox(...) afin de vrifier qu'elles sont bien appeles.
Si l'on jette un coup d'il la documentation officielle concernant le wxButton
(http://www.wxwidgets.org/manuals/stable/wx_wxbutton.html), la rubrique Event handling (gestion des
vnements), il est dit que ce contrle ragit un wxEVT_COMMAND_BUTTON_CLICKED . Le dbut de cette
constante nous permet de savoir que les mthodes que nous allons avoir crer devront possder un paramtre de type
wxCommandEvent, afin que l'on puisse rcuprer quelques informations sur le contrle qui a gnr cet vnement.
Ce type d'vnement est celui que vous aurez le plus souvent utiliser dans vos programmes wxWidgets (pour les
menus, les contrles basiques tels que les boutons radio, les cases cocher, ...).
Il y a malgr tout plusieurs types d'vnements, et tous n'utilisent pas le wxCommandEvent. Ainsi, le wxListCtrl
utilise un wxListEvent, qui contiendra des informations spcifiques au wxListCtrl.
Pour plus d'infos sur la gestion des vnements sous wxWidgets, je vous recommande vivement de lire larticle qui
y est consacr dans la documentation officielle (il est malheureusement en anglais, mais il permet den comprendre les
grands principes) : http://www.wxwidgets.org/manuals/stable/wx_eventhandlingoverview.html.
Une dernire petite chose : chaque vnement est transmis la mthode qui lui est associe par sa rfrence.
Pour ajouter ces deux mthodes la classe MainFrame, il suffit d'ajouter leur dclaration dans le header cette
classe, et leur dfinition dans le fichier source, mais a, vous le saviez dj, en tant que bon programmeur.C++.
Ce qui donne, pour le fichier mainframe.h :
#ifndef MAINFRAME_H_INCLUDED
#define MAINFRAME_H_INCLUDED
// On ajoute les headers "basiques" de wxWidgets
#include <wx/wx.h>
// On ajoute le header du contrle wxListCtrl, qui n'est pas inclus
// Dans les headers "basiques"
#include <wx/listctrl.h>
// Dfinition de la classe "MainFrame"
class MainFrame : public wxFrame
{
public:
// Le constructeur
MainFrame();
// Le destructeur
~MainFrame();
private:
// Dclaration des mthodes vnementielles
void OnButtonBrowseClicked(wxCommandEvent &event);
void OnButtonStartClicked(wxCommandEvent &event);
// Les pointeurs vers les wxTextCtrl pour le nom/les jockers et le dossier de dmarrage
wxTextCtrl *txtName, *txtPath;
// Les pointeur vers les boutons "Parcourir" et "Dmarrer"
wxButton *btnBrowse, *btnStart;
// Les identifiants pour ces mme boutons
static const int ID_BTN_BRWSE,ID_BTN_START;

// Le pointeur vers la wxStaticBox de droite pour l'affichage du nombre de rsultats trouvs


wxStaticBox *stbNumRes;
// Le pointeur vers le wxListCtrl pour l'affichage des rsultats.
wxListCtrl *lstResults;
};
#endif // MAINFRAME_H_INCLUDED

Et, pour le fichier mainframe.cpp (je ne mets ici que les lignes ajouter la fin du fichier, pour ne pas surcharger le
cours) :
void MainFrame::OnButtonBrowseClicked(wxCommandEvent &event)
{
wxMessageBox(_T("Appel de la mthode 'OnButtonBrowseClicked'"));
}
void MainFrame::OnButtonStartClicked(wxCommandEvent &event)
{
wxMessageBox(_T("Appel de la mthode 'OnButtonStartClicked'"));
}

C'est tout. Vous pouvez compiler si a vous chante, mais de toute faon, il ne va rien se passer, car nous n'avons
pas connect les clics sur les boutons leur mthodes respectives.
C'est ce que nous allons voir maintenant.
Pour que notre fentre puisse rediriger les vnements vers les mthodes que l'on vient de crer, il faut
imprativement dclarer (dans le header) et dfinir (dans le fichier cpp) une table des vnements .
Pour la dclaration, il suffit d'ajouter la macro DECLARE_EVENT_TABLE() dans le header de notre classe
MainFrame (fichier mainframe.h).
#ifndef MAINFRAME_H_INCLUDED
#define MAINFRAME_H_INCLUDED
// On ajoute les headers "basiques" de wxWidgets
#include <wx/wx.h>
// On ajoute le header du contrle wxListCtrl, qui n'est pas inclus
// Dans les headers "basiques"
#include <wx/listctrl.h>
// Dfinition de la classe "MainFrame"
class MainFrame : public wxFrame
{
public:
// Le constructeur
MainFrame();
// Le destructeur
~MainFrame();
private:
// Dclaration des mthodes vnementielles
void OnButtonBrowseClicked(wxCommandEvent &event);
void OnButtonStartClicked(wxCommandEvent &event);
// Les pointeurs vers les wxTextCtrl pour le nom/les jockers et le dossier de dmarrage
wxTextCtrl *txtName, *txtPath;
// Les pointeur vers les boutons "Parcourir" et "Dmarrer"
wxButton *btnBrowse, *btnStart;
// Les identifiants pour ces mme boutons
static const int ID_BTN_BRWSE,ID_BTN_START;
// Le pointeur vers la wxStaticBox de droite pour l'affichage du nombre de rsultats trouvs
wxStaticBox *stbNumRes;
// Le pointeur vers le wxListCtrl pour l'affichage des rsultats.
wxListCtrl *lstResults;
// Dclaration de la table des vnements
DECLARE_EVENT_TABLE();
};
#endif // MAINFRAME_H_INCLUDED

Pour la dfinition, il faut utiliser deux macros : une premire pour marquer le dbut de la table des
vnements (BEGIN_EVENT_TABLE(...,...)), et qui prend en paramtres le nom de notre classe, ainsi que
celui de celle dont elle drive, ainsi qu'une autre pour fermer cette table (END_EVENT_TABLE).

Comme je vous l'ai dit prcdemment, nous allons utiliser deux techniques diffrentes pour connecter les
boutons aux mthodes de la fentre.
La premire consiste ajouter une macro dans la dfinition de la table des vnements. Cette macro, par son
nom, dfinira le type d'vnement grer (clic sur un bouton dans notre cas), et prendra en paramtre
l'identifiant du bouton (que nous avons dfini dans le chapitre 2), et le nom de la mthode associer.
La deuxime consistera connecter le bouton au moment de sa cration, par l'intermdiaire de la mthode
wxEventHandler::Connect(...) (notre fentre est drive de wxFrame, drive de wxTopLevelWindow, drive
de wxWindow, drive de wxEventHandler).
Nous allons donc utiliser la premire solution (qui est d'ailleurs la plus souvent utilise), pour connecter le bouton
parcourir la mthode MainFrame::OnButtonBrowseClicked.
Nous voulons grer l'vnement clic sur un bouton . En regardant la documentation officielle, on peut voir que
cela se fait avec la macro EVT_BUTTON(identifiant,mthode_associe).
Voici ce que a donne (fichier mainframe.cpp):
// On affecte les identifants des deux boutons
const int MainFrame::ID_BTN_BRWSE = wxNewId();
const int MainFrame::ID_BTN_START = wxNewId();
// Dfinition de la table des vnements
BEGIN_EVENT_TABLE(MainFrame,wxFrame)
// Connection du bouton "Parcourir" la mthode MainFrame::OnButtonBrowseClicked
EVT_BUTTON(ID_BTN_BRWSE,MainFrame::OnButtonBrowseClicked)
END_EVENT_TABLE()
// Le constructeur
MainFrame::MainFrame() : wxFrame(NULL,wxID_ANY,_T("FileFinder"))
{
// .........
}

Vous pouvez dsormais compiler, et tester le bouton parcourir : vous devriez obtenir un petit message vous
indiquant que l'appel de la mthode MainFrame::OnButtonBrowseClicked s'est bien effectu correctement :

Comme vous pouvez le voir, c'tait tout simple, et a marche merveille.


Voici quelques petites prcisions sur cette technique :
Il est facile, par un simple coup d'il dans la table des vnements, de retrouver quelle mthode est connect un
bouton, ou n'importe quel contrle (si bien sr vous avez donne un nom explicite vos identifiants).
Il est possible de connecter plusieurs contrles la mme mthode (dans notre exemple, si vous ajoutez
EVT_BUTTON(ID_BTN_START,MainFrame::OnButtonBrowseClicked) dans la table des vnements, un clic sur le
bouton Dmarrer fera apparatre le mme message que pour le bouton Parcourir ).
Le problme, c'est que tout est dfini au moment de la compilation. Il n'est plus possible d'utiliser ces macros lors
de l'excution (ce qui peut tre utile, par exemple pour des menus dont le contenu change en fonction de ce qui est
slectionn).
Nous allons maintenant nous attaquer la deuxime technique pour connecter un contrle (dans notre cas le bouton
Dmarrer ) une mthode.
Comme je vous l'ai dit plus haut, la connexion se fait au moment de la cration du contrle (en fait, elle peut se
faire n'importe o et n'importe quand, mais jai pris lhabitude de la faire tout de suite aprs avoir cr le contrle).
On utilise dans ce cas la mthode wxEventHandler::Connect(...)
Le premier paramtre est l'identifiant du bouton, c'est dire, dans notre cas, ID_BTN_START.

Le deuxime correspond au type d'vnement que lon veut grer : pour un clic sur un bouton, c'est
wxEVT_COMMAND_BUTTON_CLICKED. Vous pouvez retrouver le nom de cette macro dans la documentation
officielle concernant le wxButton, rubrique Event Handling :
http://www.wxwidgets.org/manuals/stable/wx_wxbutton.html
Pour le troisime, c'est un peu plus compliqu. Retenez simplement qu'il faut passer une wxObjectEventFunction.
Regardez
la
documentation
officielle
concernant
la
mthode
wxEventHandler::Connect()
(http://www.wxwidgets.org/manuals/stable/wx_wxevthandler.html#wxevthandlerconnect), il y a un petit exemple.
Ainsi, pour un vnement de type wxCommandEvent, il faut donner ce paramtre grce
wxCommandEventHandler(Nom_de_la_mthode). Pour un vnement de type wxSizeEvent, on aurait mis
wxSizeEventHandler(MainFrame::OnSize), et ainsi de suite.
Ce qui donne (je vous laisse retrouver o a va dans le fichier mainframe.cpp):
// Le bouton "Dmarrer"
btnStart=new wxButton(this,ID_BTN_START,_T("Dmarrer"));
Connect(ID_BTN_START,wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(MainFrame::OnButtonStartClicked));
// On l'ajoute au sizer vertical
left_vsizer->Add(btnStart,0,wxALL|wxALIGN_RIGHT,5);

Et voil, c'est tout aussi simple (et aussi efficace) que la premire solution.
L'avantage de celle-ci, c'est que l'on peut regrouper la cration du contrle, et sa connexion une mthode.
Un autre avantage (et non des moindres) est que la connexion peut se faire en cours d'excution du programme, ce
que ne permet pas la technique prcdente.
Il est galement possible de dconnecter un contrle d'une mthode grce la classe wxEventHandler dont est
drive notre fentre.
Il n'empche que mme si vous dcidez de n'utiliser que cette solution, vous devez quand mme faire la dclaration
et la dfinition de la table des vnements (qui dans ce cas sera vide).
Voil, nous avons russi connecter nos deux boutons leurs mthodes respectives.
Il ne nous reste plus qu' placer le bon code dans ces mthodes, et notre petit utilitaire sera fonctionnel.

Chapitre 4 : Le code pour slectionner le dossier de dmarrage


Notre interface est maintenant en place, et fonctionnelle (mme si, pour l'instant, seules des petites botes de
message s'affichent lorsque lon clique sur les boutons).
Nous allons maintenant crire le code correspondant la mthode MainFrame::OnButtonBrowseClicked().
Cette mthode est appele lorsque l'utilisateur clique sur le bouton Parcourir , et doit permettre la slection du
dossier dans lequel va commencer la recherche.
Cette slection de dossier se fait par l'intermdiaire de la classe wxDirDialog qui a t cre spcialement pour cela
(http://www.wxwidgets.org/manuals/stable/wx_wxdirdialog.html).
Si l'on jette un coup d'il la documentation officielle concernant le constructeur de cette classe, on peut voir qu'il
lui faut comme paramtres :
Un pointeur vers la fentre parente.
Le message afficher dans la boite de dialogue de slection.
Le rpertoire prslectionn.
Le style de cette boite (nous indiquerons le style wxDD_DIR_MUST_EXIST).
Pour les autres paramtres, nous laisserons les valeurs par dfaut.
Aprs avoir affich cette bote de dialogue, et si l'utilisateur n'a pas cliqu sur le bouton Annuler qu'elle
contient, il nous suffira de rcuprer le chemin complet du rpertoire slectionn, et de l'afficher dans le wxTextCtrl
correspondant (dont nous avons stock le pointeur dans la variable txtPath).

Ce qui donne comme code (en remplacement du simple appel la fonction wxMessageBox dans le fichier
mainframe.cpp):
#include <wx/dirdlg.h>
void MainFrame::OnButtonBrowseClicked(wxCommandEvent &event)
{
// On cre le wxDirDialog
wxDirDialog dirdlg(this, // La fentre parente
_T("Slectionnez le dossier dans lequel commencer la recherche"), // Le message
_T(""), // Le dossier par dfaut
wxDD_DIR_MUST_EXIST); // Le style de la boite de dialogue
// On l'affiche jusqu' ce que l'utilisateur ait cliqu sur "Ok" ou "Annuler"
int result=dirdlg.ShowModal();
// Si le bouton "Annuler" a t press, alors, on sort
if (result==wxID_CANCEL) return;
// Sinon, on rcupre le chemin complet du dossier slectionn
wxString sPath=dirdlg.GetPath();
// Et on l'affiche dans le wxTextCtrl correspondant
txtPath->SetValue(sPath);
}

Voil, ce n'est pas plus compliqu que cela.


Vous pouvez compiler et tester, a marche !

Chapitre 5 : La recherche des fichiers et des dossiers


Il ne nous manque plus que l'essentiel : la recherche des fichiers proprement dite ; aprs cela, notre application sera
fonctionnelle.
Il nous faut donc crire le code de la mthode MainFrame::OnButtonStartClicked().
Voici ce quelle devra effectuer :
Lancer l'numration des fichiers et sous/dossiers contenus dans le rpertoire de dpart.
Ajouter les fichiers et les dossiers trouvs au wxListCtrl pour l'affichage des rsultats de la recherche.
Pour obtenir la liste des fichiers/dossiers, nous disposons d'une classe spcialement tudie pour grer les actions
relatives un rpertoire : wxDir (http://www.wxwidgets.org/manuals/stable/wx_wxdir.html).
Cette classe nous propose 3 possibilits pour obtenir le listing du contenu d'un dossier :
La mthode GetFirst() - GetNext() : avec cette mthode, nous allons devoir nous dbrouiller pour

lister le contenu des ventuels sous-dossiers.


La mthode GetAllFiles() : l'inconvnient de cette mthode est qu'elle ne nous rend pas la main avant d'avoir
fini l'numration du contenu. L'utilisateur ne pourrait pas annuler la recherche si celle-ci devient trop longue.

De plus, le rsultat de l'numration est plac dans un wxArrayString, ce qui peut vite prendre beaucoup de
mmoire inutilement.
La mthode Traverse() : Trs simple d'utilisation, cette mthode ncessite par contre la cration d'une classe
supplmentaire : la classe wxDirTraverser. C'est la mthode que nous allons utiliser.
Pour utiliser cette dernire mthode, il nous faut d'abord crer une classe drive de wxDirTraverser()
(http://www.wxwidgets.org/manuals/stable/wx_wxdirtraverser.html). Cette classe contiendra les mthodes OnFile() et
OnDir() qui seront appeles pour chaque fichier/dossier que wxDir::Traverse() trouvera.
Ensuite, lorsqu'on lance la recherche, on passe une instance de cette classe la mthode wxDir::Traverse().
Pour chaque fichier trouv, un appel est fait wxDirTraverser::OnFile().
Pour chaque dossier (vous l'aurez devin), un appel est fait wxDirTraverser::OnDir().
C'est donc l'intrieur de ces deux fonctions que nous allons placer le code pour ajouter le rsultat au wxListCtrl.
Nous y placerons galement un bout de code pour vrifier si l'utilisateur a ventuellement demand de stopper la
recherche.
A ce sujet, nous devons proposer l'utilisateur cette possibilit. Pour ce faire, nous allons simplement changer le
texte du bouton Dmarrer en Arrter . Il suffira donc, dans l'appel de la mthode associe ce bouton, de
regarder quel est le texte du bouton, pour savoir ce que l'on doit faire :
Si le texte est Dmarrer , alors, il faut dmarrer la recherche.
Si le texte est Arrter , alors il faut stopper tout.
Pour demander l'arrt (ou au contraire, autoriser la continuit) de la recherche, tout se passe dans les mthodes
wxDirTraverser::OnFile() et wxDirTraverser::OnDir(). En effet, ces deux mthodes doivent renvoyer une valeur de
type wxDirTraverseResult qui peut prendre les valeurs suivantes:
wxDIR_IGNORE : Ignorer le contenu du rpertoire qui vient d'tre trouv.
wxDIR_STOP : Arrter l'numration (intressant, non ?).
wxDIR_CONTINUE : Vous avez devin : continuer l'numration.
Pour indiquer au wxDirTraverser qu'il doit stopper l'numration, il suffit d'ajouter une variable statique de type
boolen dans la mthode MainFrame::OnButtonStartClicked() et de lui en passer le pointeur en paramtre, et le tour
est jou.
Voici, concrtement ce que a va donner.
En premier lieu, nous devons crer la classe drive de wxDirTraverser. Nous l'appellerons DirTraverser, tout
simplement.
Commencez donc par ajouter deux fichiers vides (menu File New Empty file, rpondez Oui lorsqu'on
vous demande si vous dsirez les ajouter au projet courant, et nommez-les respectivement dirtraverser.h et
dirtraverser.cpp.
Voici leur contenu initial (nous complterons par la suite).
La dclaration de la classe (fichier dirtraverser.h) :
#ifndef DIRTRAVERSER_H_INCLUDED
#define DIRTRAVERSER_H_INCLUDED
#include <wx/dir.h>
class DirTraverser : public wxDirTraverser
{
public:
// Le constructeur : on lui passe en paramtres le pointeur vers le wxListCtrl
// pour l'ajout des rsultats, ainsi que le pointeur vers la variable de type
// boolen pour l'arrt de l'numration
DirTraverser(wxListCtrl *lstResults, bool *stopFlag);
// La mthode appele lorsqu'un fichier est trouv
virtual wxDirTraverseResult OnFile(const wxString &filename);
// La mthode appele lorsqu'un dossier est trouv
virtual wxDirTraverseResult OnDir(const wxString &dirname);
private:
// Les variables pour stocker les pointeurs passs en paramtres au constructeur
wxListCtrl *m_lstResults;
bool *m_bStopFlag;
};
#endif // DIRTRAVERSER_H_INCLUDED

La dfinition de la classe (fichier dirtraverser.cpp) :


#include "dirtraverser.h"

DirTraverser::DirTraverser(wxListCtrl *lstResults, bool *stopFlag)


{
// On stocke les deux pointeurs passs en paramtres
m_lstResults=lstResults;
m_bStopFlag=stopFlag;
}
wxDirTraverseResult DirTraverser::OnFile(const wxString &filename)
{
// Cette mthode sera appele pour chaque fichier trouv
return wxDIR_CONTINUE;
}
wxDirTraverseResult DirTraverser::OnDir(const wxString &dirname)
{
// Cette mthode sera appele pour chaque dossier trouv
return wxDIR_CONTINUE;
}

Voil : rien de bien particulier, car tout a t expliqu avant.


Nous allons maintenant crire le code de la mthode MainFrame::OnButtonStartClicked(), et nous reviendrons
plus tard pour finaliser la classe DirTraverser.
Tout d'abord, pour pouvoir utiliser le DirTraverser que nous venons de crer, il faut ajouter le header de cette
classe au dbut du fichier mainframe.cpp.
Puis, dans la mthode MainFrame::OnButtonStartClicked(), nous allons placer la dclaration de la variable statique
qui va nous servir pour demander l'arrt de la recherche:
static bool bStopFlag;

Viendra ensuite la condition pour savoir si l'on veut dmarrer la recherche, ou l'arrter :
if(btnStart->GetLabel()==_T("Dmarrer"))
{
// Placer ici le code pour lancer la recherche
} else {
// Placer ici le code pour stopper la recherche
}

Occupons nous dans un premier temps de la portion de code pour stopper la recherche : nous avons dit plus haut qu'il
suffisait de modifier la valeur de la variable statique bStopFlag.
Ce qui nous donne :
bStopFlag=true;

C'est tout. Nous nous chargerons, chaque appel de DirTraverser::OnFile() et DirTraverser::OnDir(), de regarder
la valeur de cette variable puisque nous disposerons de son pointeur.
Maintenant, la portion de code pour lancer la recherche :
Il faut d'abord vrifier que le rpertoire dans lequel nous allons dmarrer la recherche soit valide :
// On rcupre le rpertoire dans lequel faire la recherche
wxString sFolder=txtPath->GetValue();
// On vrifie que ce rpertoire existe bien, sinon, on sort
if (!wxDir::Exists(sFolder)) return;

Maintenant que l'on a vrifi la validit du rpertoire, on peut lancer la recherche.


Il faut d'abord modifier le label du bouton Dmarrer pour mettre Arrter la place.
btnStart->SetLabel(_T("Arrter"));

Ensuite, on peut construire l'objet wxDir :


wxDir dir(sFolder);

Puis finalement lancer la recherche en crant au passage un objet DirTraverser et en s'assurant que le boolen soit
bien rinitialis :
bStopFlag=false;
DirTraverser traverser(lstResults,&bStopFlags);
dir.Traverse(traverser,txtName->GetValue(),wxDIR_DIRS|wxDIR_FILES);

Vous aurez remarqu, au passage, le deuxime paramtre qui correspond au masque de recherche.
Lorsque la fonction wxDir::Traverse() nous rend la main, c'est que la recherche est termine, ou que l'on a
demand son arrt.
On peut donc remettre le label du bouton "Dmarrer" sa valeur d'origine :
btnStart->SetLabel(_T("Dmarrer"));

Et c'est tout.
Voici donc un rcapitulatif du code de la mthode MainFrame::OnButtonStartClicked():
void MainFrame::OnButtonStartClicked(wxCommandEvent &event)
{
static bool bStopFlag;
if(btnStart->GetLabel()==_T("Dmarrer"))
{
// On rcupre le rpertoire dans lequel faire la recherche
wxString sFolder=txtPath->GetValue();
// On vrifie que ce rpertoire existe bien, sinon, on sort
if (!wxDir::Exists(sFolder)) return;
// On change le label du bouton "Dmarrer" en "Arrter"
btnStart->SetLabel(_T("Arrter"));
// On construit l'objet wxDir
wxDir dir(sFolder);
// On construit l'objet DirTraverser
DirTraverser traverser(lstResults,&bStopFlag);
// On r-initialise le boolen
bStopFlag=false;
// Et on lance la recherche
dir.Traverse(traverser,txtName->GetValue(),wxDIR_DIRS);
// Quand on arrive ici, c'est que la recherche est termine
// On peut donc remettre le label du bouton "Dmarrer"
btnStart->SetLabel(_T("Dmarrer"));
} else {
bStopFlag=true;
}
}

Bien, maintenant, il ne nous reste plus qu' crire le code des methodes OnFile() et OnDir() de notre DirTraverser.
Elles doivent faire toutes les deux sensiblement la mme chose :
Ajouter le fichier/dossier qui leur est transmis en paramtre dans le wxListCtrl
Vrifier l'tat du boolen pour ventuellement arrter la recherche en cours
La seule diffrence est le texte qui doit tre affich dans la deuxime colonne du wxListCtrl : Fichier ou
Dossier .
Pour ne pas avoir retaper deux fois le mme code, nous allons ajouter une mthode AddItemToListCtrl() au
DirTraverser, et lui passer en paramtre le nom du fichier/dossier ajouter, ainsi que le texte mettre dans la
deuxime colonne.
Cette mthode se chargera de sparer le nom du fichier/dossier de son emplacement, vrifiera l'tat du boolen, et
renverra la valeur que les fonctions OnFile et OnDir doivent retourner pour la suite ou l'arrt de la recherche.

Commenons donc par ajouter la dclaration de cette nouvelle mthode (fichier dirtraverser.h):
#ifndef DIRTRAVERSER_H_INCLUDED
#define DIRTRAVERSER_H_INCLUDED
#include <wx/dir.h>
#include <wx/listctrl.h>
class DirTraverser : public wxDirTraverser
{
public:
// Le constructeur : on lui passe en paramtres le pointeur vers le wxListCtrl
// pour l'ajout des rsultats, ainsi que le pointeur vers la variable de type
// boolen pour l'arrt de l'numration
DirTraverser(wxListCtrl *lstResults, bool *stopFlag);
// La mthode appele lorsqu'un fichier est trouv
virtual wxDirTraverseResult OnFile(const wxString &filename);
// La mthode appele lorsqu'un dossier est trouv
virtual wxDirTraverseResult OnDir(const wxString &dirname);
private:
// La mthode qui va faire tout le travail pour les deux ci-dessus
wxDirTraverseResult AddItemToListCtrl(const wxString &item, const wxString &type);
// Les variables pour stocker les pointeurs passs en paramtres au constructeur
wxListCtrl *m_lstResults;
bool *m_bStopFlag;
};
#endif

Grce cette mthode, le code des deux fonction OnFile() et OnDir() est normment simplifi :
wxDirTraverseResult DirTraverser::OnFile(const wxString &filename)
{
return AddItemToListCtrl(filename,_T("Fichier"));
}
wxDirTraverseResult DirTraverser::OnDir(const wxString &dirname)
{
return AddItemToListCtrl(dirname,_T("Dossier"));
}

Et comme je vous l'ai dit, c'est la mthode AddItemToListCtrl() qui va tout faire.
D'abord, sparer le nom du fichier de son emplacement. Pour cela, on recherche le dernier caractre correspondant
au sparateur de dossiers dans un chemin, savoir \ pour Windows, et / pour les autres OS.
Et comme wxWidgets nous propose quelque chose de tout prt pour obtenir ce caractre, on ne va pas se priver de
s'en servir. Il est rcuprable grce wxFileName::GetPathSeparator(). Il faudra donc penser ajouter le header de
wxFileName (<wx/filename.h>) au dbut du fichier dirtraverser.cpp pour y avoir accs.
int i=item.Find(wxFileName::GetPathSeparator(),true);
wxString sPath=item.Left(i-1);
wxString sName=item.Right(item.Length()-i);

Ensuite, il faut ajouter l'lment la liste des rsultats, grce wxListCtrl::InsertItem().


long itemIndex=m_lstResults->InsertItem(0,sName);

Puis mettre le texte correspondant la deuxime colonne :


m_lstResults->SetItem(itemIndex,1,type);

Puis placer le chemin dans la troisime colonne


m_lstResults->SetItem(itemIndex,2,sPath);

Il ne reste plus qu' vrifier l'tat du boolen pour renvoyer la bonne valeur, mais avant, il faut que l'on insre un
petit appel la fonction wxYield() pour permettre l'interface de se mettre jour :
wxYield();
return (*m_bStopFlag==true)?wxDIR_STOP:wxDIR_CONTINUE;

Voici donc un rcapitulatif du fichier dirtraverser.cpp :


#include "dirtraverser.h"
#include <wx/filename.h>
DirTraverser::DirTraverser(wxListCtrl *lstResults, bool *stopFlag)
{
// On stocke les deux pointeurs passs en paramtres
m_lstResults=lstResults;
m_bStopFlag=stopFlag;
}
wxDirTraverseResult DirTraverser::OnFile(const wxString &filename)
{
return AddItemToListCtrl(filename,_T("Fichier"));
}
wxDirTraverseResult DirTraverser::OnDir(const wxString &dirname)
{
return AddItemToListCtrl(dirname,_T("Dossier"));
}
wxDirTraverseResult DirTraverser::AddItemToListCtrl(const wxString &item, const wxString &type)
{
// On rcupre la position du dernier sparateur
int i=item.Find(wxFileName::GetPathSeparator(),true);
// On spare le nom et le chemin
wxString sPath=item.Left(i);
wxString sName=item.Right(item.Length()-i-1);
// On ajoute tout a la liste des rsultats
long itemIndex=m_lstResults->InsertItem(0,sName);
m_lstResults->SetItem(itemIndex,1,type);
m_lstResults->SetItem(itemIndex,2,sPath);
// Pour permettre l'interface de se rafrachir
wxYield();
// Et on retourne la bonne valeur, en fonction du boolen
return (*m_bStopFlag==true) ? wxDIR_STOP : wxDIR_CONTINUE;
}

Voil, c'est termin.


Vous pouvez compiler, et tester l'application : elle est fonctionnelle. Il reste bien entendu quelques petites choses
amliorer, mais a fonctionne !
Pour information, deux petits bugs se sont glisss dans le code (ils ne sont pas trs mchants, mais ils font que les
rsultats obtenus ne sont pas forcment ceux recherchs).

Chapitre 6 : Quelques optimisations


Tout d'abord, je ne sais pas si vous l'avez remarqu, mais si vous lancez deux recherches sans fermer l'application,
les rsultats s'ajoutent dans la liste. Cest le premier petit bug dont je vous parlais la fin du chapitre prcdent.
Cela vient du fait que nous n'avons jamais donn d'instruction pour vider cette liste au dbut de la recherche.
Il est trs facile de corriger cela, en ajoutant une instruction juste avant de lancer cette recherche (fichier
mainframe.cpp):
lstResults->DeleteAllItems();

Deuxime petite chose : souvenez-vous, lors de la cration de l'interface, nous avions gard un pointeur vers la
wxStaticBox entourant la liste des rsultats, afin de pouvoir en changer le texte, et ainsi informer l'utilisateur du
nombre d'lments trouvs.

Justement, wxDir::Traverse() (http://www.wxwidgets.org/manuals/stable/wx_wxdir.html#wxdirtraverse) va nous


donner en retour le nombre dont on a besoin. Il suffit donc de le rcuprer, et de changer le texte de la wxStaticBox
(fichier mainframe.cpp):
// Et on lance la recherche
size_t count=dir.Traverse(traverser,txtName->GetValue(),wxDIR_DIRS|wxDIR_FILES);
// Quand on arrive ici, c'est que la recherche est termine
// On peut donc remettre le label du bouton "Dmarrer"
btnStart->SetLabel(_T("Dmarrer"));
// ainsi que le texte de la wxStaticBox entourant la liste des rsultats
stbNumRes->SetLabel(wxString::Format(_T("Rsultats de la recherche : %0ld lments
trouvs"),count));

Ensuite, nous allons rsoudre le deuxime petit bug de cette application.


En effet, lorsqu'on lance une recherche, tous les sous-dossiers du rpertoire de dpart sont ajouts aux rsultats de
la recherche, alors quil ne devrait y avoir que ceux dont le nom correspond au masque de recherche..
Cela est d au fait que la mthode DirTraverser::OnDir(...) est appele pour chaque sous-dossier rencontr,
contrairement la mthode DirTraverser::OnFile(...) qui est appele uniquement quand le nom du fichier correspond
au critres de la recherche.
Qu' cela ne tienne, nous allons lgrement modifier notre classe DirTraverser afin qu'elle puisse tester les noms
des dossiers avant de les ajouter la liste des rsultats.
Tout d'abord, il faut que cette classe ait accs au masque de recherche. Nous allons tout simplement le lui passer en
paramtre de construction, et le stocker dans une variable wxString prive. Au moment de la recherche, comme le nom
du dossier tester est pass la mthode OnDir(...) grce un wxString, et que cette classe possde une mthode
Matches permettant de savoir si le wxString correspond un masque de recherche, notre petit bug sera vite corrig (il
faudra quand mme que l'on fasse l'extraction du nom du dossier car c'est son chemin complet qui est pass
lamthode OnDir(...)).
Voici donc, dans un premier temps, le code de la classe DirTraverser modifi :
Le fichier dirtraverser.h
#ifndef DIRTRAVERSER_H_INCLUDED
#define DIRTRAVERSER_H_INCLUDED
#include <wx/dir.h>
#include <wx/listctrl.h>
class DirTraverser : public wxDirTraverser
{
public:
// Le constructeur : on lui passe en paramtres le pointeur vers le wxListCtrl
// pour l'ajout des rsultats, ainsi que le pointeur vers la variable de type
// boolen pour l'arrt de l'numration
DirTraverser(wxListCtrl *lstResults, const wxString mask, bool *stopFlag);
// La mthode appele lorsqu'un fichier est trouv
virtual wxDirTraverseResult OnFile(const wxString &filename);
// La mthode appele lorsqu'un dossier est trouv
virtual wxDirTraverseResult OnDir(const wxString &dirname);
private:
// La mthode qui va faire tout le travail pour les deux ci-dessus
wxDirTraverseResult AddItemToListCtrl(const wxString &item, const wxString &type);
// Les variables pour stocker les pointeurs passs en paramtres au constructeur
wxListCtrl *m_lstResults;
bool *m_bStopFlag;
// La variable pour stocker le masque de recherche
// (correction du premier bug de notre application)
wxString m_mask;
};
#endif

Le fichier dirtraverser.cpp
#include "dirtraverser.h"
#include <wx/filename.h>
DirTraverser::DirTraverser(wxListCtrl *lstResults, const wxString mask, bool *stopFlag)
{
// On stocke les deux pointeurs passs en paramtres
m_lstResults=lstResults;
m_bStopFlag=stopFlag;
// On stocke galement le masque de recherche
m_mask=mask;
}
wxDirTraverseResult DirTraverser::OnFile(const wxString &filename)
{
return AddItemToListCtrl(filename,_T("Fichier"));
}
wxDirTraverseResult DirTraverser::OnDir(const wxString &dirname)
{
// On rcupre le nom du dossier
int i=dirname.Find(wxFileName::GetPathSeparator(),true);
wxString sName=dirname.Right(dirname.Length()-i-1);
// On teste s'il correspond au masque de recherche
if (sName.Matches(m_mask))
{
// Si c'est le cas, on l'ajoute la liste des rsultats
return AddItemToListCtrl(dirname,_T("Dossier"));
} else {
// Sinon, on passe ventuellement la suite
return (*m_bStopFlag==true)?wxDIR_STOP:wxDIR_CONTINUE;
}
}
wxDirTraverseResult DirTraverser::AddItemToListCtrl(const wxString &item, const wxString &type)
{
// On rcupre la position du dernier sparateur
int i=item.Find(wxFileName::GetPathSeparator(),true);
// On spare le nom et le chemin
wxString sPath=item.Left(i);
wxString sName=item.Right(item.Length()-i-1);
// On ajoute tout a la liste des rsultats
long itemIndex=m_lstResults->InsertItem(0,sName);
m_lstResults->SetItem(itemIndex,1,type);
m_lstResults->SetItem(itemIndex,2,sPath);
// Pour permettre l'interface de se rafrachir
wxYield();
// Et on retourne la bonne valeur, en fonction du boolen
return (*m_bStopFlag==true)?wxDIR_STOP:wxDIR_CONTINUE;
}

Il reste maintenant modifier le code crant une instance de cette classe, dans le fichier mainframe.cpp. en ajoutant
le masque de recherche aux paramtres de construction du DirTraverser.
Cela se passe dans la mthode MainFrame::OnButtonStartClicked(...).
Il faut remplacer
DirTraverser traverser(lstResults,&bStopFlag);

par
DirTraverser traverser(lstResults,txtName->GetValue(),&bStopFlag);

Il reste une dernire petite chose rgler : Nous avons utilis la fonction wxYield() qui est depuis quelques versions
dclare comme dprcie . Il faut la remplacer par la mthode wxApp::Yield().
Si vous vous penchez une dernire fois sur la documentation officielle pour wxApp, et plus prcisment sur la partie
concernant wxApp::Yield(), vous vous apercevrez que cette mthode nest pas statique. Il faut donc appeler la mthode

Yield() membre de notre instance de classe dapplication. Or, je ne sais pas si vous vous en souvenez, mais nous
navons jamais cr de variable de type FileFinderApp.
Nous avons seulement utilis la macro IMPLEMENT_APP(FileFinderApp) qui sest elle-mme charge den crer
une instance.
Malgr tout, les concepteurs de wxWidgets ont tout prvu. Dans le fichier header de la classe FileFinderApp, juste
aprs sa dclaration, nous avons ajout une autre macro : DECLARE_APP(FileFinderApp).
Cette macro, comme je vous lai vaguement dit au dbut de ce cours, va se charger de crer une fonction
wxGetApp() qui va nous renvoyer une rfrence vers linstance de notre classe dapplication en cours dutilisation.
Il nous suffit donc dinclure le header contenant cette macro (le fichier filefinderapp.h) quand nous en aurons
besoin, et nous pourrons obtenir une variable de type FileFinderApp&.
La commande wxYield() que nous devons remplacer se trouve dans le fichier dirtraverser.cpp. Il faut donc ajouter
au dbut de ce fichier :
#include "filefinderapp.h"

Ensuite, il suffit de remplacer la commande wxYield() (dans la mthode DirTraverser::AddItemToListCtrl() )


par les lignes ci-dessous :
FileFinderApp& myapp=wxGetApp();
Myapp.Yield();

Nous pouvons mme faire plus simple, car il est inutile de crer une variable juste pour cela :
wxGetApp().Yield();

Et voil, ctait tout simple.


A noter que la commande wxGetApp() peut aussi vous servir appeler une mthode spcifique votre classe
dapplication. Si par exemple, nous avions cr une mthode publique FileFinderApp::GetApplicationPath() pour
rcuprer le chemin de lapplication (ce nest quun exemple, ne le faites pas), nous pourrions lappeler par
wxGetApp().GetApplicationPath().

Conclusion
Voil : cette premire partie est maintenant termine.
Jespre quelle vous aura donn lenvie duser et dabuser de wxWidgets.
Il est vrai qu lorigine, javais lintention dajouter des fonctionnalits notre petit utilitaire, comme la possibilit
de spcifier une chaine de caractres rechercher dans les fichiers, et bien dautres encore, mais je pense que nous
verrons cela dans la deuxime partie de ce cours.
Pour ceux que a intresse, il vous est possible de tlcharger le projet associ ce cours sur ma page perso :
Le projet Code::Blocks Win32 (avec l'excutable compil en statique) : sous forme darchive 7zip (505Ko)
http://x.psoud.free.fr/localfiles/articles/tutowxwidgets1/FileFinder_w32.7z
Le projet Code::Blocks Linux : sous forme darchive tarball (5Ko) :
http://x.psoud.free.fr/localfiles/articles/tutowxwidgets1/FileFinder_CB.tar.gz
Le projet Linux "Makefile" : sous forme darchive tarball (87Ko) :
http://x.psoud.free.fr/localfiles/articles/tutowxwidgets1/filefinder-1.0.tar.gz
Bien entendu, jattends avec impatience vos remarques, et critiques sur ce cours.
De mme, sil y a un point prcis de wxWidgets que vous souhaiteriez voir abord, nhsitez pas men faire part,
afin que je puisse ventuellement lintgrer dans les prochaines parties du cours.
En attendant, bonne prog, et @ + sur www.wxdev.fr.
Xav

Vous aimerez peut-être aussi