Programmation Windows - Chap. 4 - Les fenêtres de dialogue
Partie 2/3


1. Introduction.

Pour continuer notre série sur les boites de dialogue, nous allons tout simplement passer en revue quelques controles typiques et clarifier quelques notions de base. Je n'irais pas, volontairement, dans les détails concernant chaque controle. Ces tutoriaux se veulent d'abord etre une introduction et MSDN reste malgré tout une source d'informations contenant tout ce qu'il faut pour aller plus loin. Nous allons donc ici aborder quelques sujets divers sur les dialogues. Désole si ce tutorial fait plutot fourre-tout mais je pense que d'une part le but de ces quelques textes n'est pas d'etre complet mais plutot d'etre un support servant d'introduction à la programmation sous Windows et à une manière de faire en général. Pour le reste : c'est a vous de jouer :).



2. Des composantes de dialogues en vrac.

Pour résumer ce que nous savons sur les controles :
Nous avons déjà vu que les boites de dialogues sont des fenêtres à part entières. Ces dialogues sont elles memes composées de controles qui eux aussi sont des fenetres (particulières biensur mais elles n'en restent pas moins des fenetres).
Un controle est une entité à part entiere qui a un comportement et une apparence par défaut. Nous allons truffer nos GUI (Graphic User Interface ou Interface Graphique Utilisateur) de controles et nous allons pouvoir connaitre leur états grace à un mecanisme de type messages (cf. tutoriaux precedents).
En schématisant un peu les choses, tout se résume en un simple dialogue entre nous et le controle à travers un ensemble de mots qui lui sont spécifiques (les messages) et dont la sémantique (la signification) ne sera partagée que par nous et le controle (et l'OS aussi mais bon).

2.1. Les check-box.

Nous avons vu la fois précédente les boutons et leurs usages. Les check box (ou "cases à cocher") sont un autre type de controle apparenté aux boutons et facile à manipuler. Si vous ne voyez pas de quoi je veux parler, vous avez surement du en rencontrer déjà, voici à quoi ils ressemblent :





En gros ce qui nous intéresse dans ce controle c'est de savoir si il est dans un état coché ou pas et de pouvoir controler son état propre si besoin est. Et bien comme d'habitude cela va pouvoir se faire de manière très simple grace à des messages que nous allons envoyer au controle. Nous allons lui donner des ordres ou bien lui demander des informations et lui va réagir avec son comportement par défaut en éxecutant ce qu'on lui demande.

Pour connaitre l'état d'un check box il suffit de lui envoyer le message BM_GETCHECK :
SendMessage(hControlWnd, BM_GETCHECK, 0, 0);
BM_GETCHECK est le message en question qui est adressé à la fenetre consituée par le check-box. Comme on l'a vu dans le précédent tutorial, ce handle va pouvoir etre récupére grace à la fonction :
GetDlgItem(HWND hdlg, int controlID );
La valeur de retour du SendMessage nous indiquera l'état de ce controle. Si la valeur est egale à la constante BST_CHECKED et bien le check box est coché sinon il ne l'est pas. Vous devez vous douter que pour forcer l'état d'un check box il suffit de lui envoyer un message BM_SETCHECK avec dans wParam l'etat final voulu : BST_CHECKED (coché) ou BST_UNCHECKED (non coché).
Un autre moyen qui masque l'appel a SendMessage c'est d'utiliser la fonction :
IsDlgButtonChecked( HWND hwndDlg, int hButtonID);
ou en plus généraliste cette fois puisque cette fonction peut s'adapter à tout type de controle :

SendDlgItemMessage( HWND hDeNotreDialogue, WORD idDeNotreControle, WORD notreMessage, WPARAM wParam, LPARAM lParam );
Ces deux manières de faire renvoient l'état du bouton en question parmi : BST_CHECKED, BST_UNCHECKED et BST_UNDETERMINATE.

NOTE: tant qu'on y est il existe un certain nombre de fonctions assez utiles concernant les boites de dialogues. Elles permettent d'avoir plus facilement acces aux informations typiques que peut fournir un controle de type edit par exemple. Ces fonctions sont : GetDlgItemInt qui permet de recuperer une information directement transformee sous forme de chiffre entier. (Exemple : l'utilisateur a entré "100" dans un edit box et nous on s'interesse a la valeur du chiffre qu'il a rentre. Au lieu de recuperer l'information sous forme de texte puis de la convertir avec un atoi() par exemple, on peut utiliser GetDlgItemInt() ), GetDlgItemText() qui permet directement de recuperer le texte d'un controle (WM_GETTEXT). Il existe biensur des equivalents Set..() a ces fonctions (SetDlgItemText etc ... ).


2.2. Les controles EditBox.

Nous avons déjà regardé un peu les controles de type Edit. Bon je voudrais juste rajouter une chose pour vous permettre de les utiliser de manière peut etre un peu plus poussée. Il est possible de faire en sorte que les EditBox acceptent plusieurs lignes et donc puissent servir de zone permettant d'afficher une grande quantité de texte (jusqu'a 32 ko si ma mémoire est bonne). La manoeuvre à effectuer est simple. Tout d'abord il faut spécifier a Windows que l'edit box a la capacité d'accepter du texte sur plusieurs lignes. Pour cela, l'éditeur de ressource est votre ami : cochez "Multiligne" dans les propriétés de votre EditBox.





Ensuite chose TRES importante pour pouvoir effectivement afficher plusieurs lignes dans votre EditBox. Il FAUT remplacer les caractères de fin de lignes classiques du C (les caractères d'echappement "\n") par des "\r\n". La raison est que Windows utilise des caractères spéciaux comme délimiteurs de fin de ligne. (Vous n'avez jamais essayé de charger avec Notepad un texte que vous auriez pris sur une plateforme Linux ou autre ? Tout est mis bout à bout avec des | qui marquent les endroits oú les fin de lignes sont censèes se trouver). Par exemple, pour écrire les chaines suivantes "Roger est grand", "Maman est gentille" et "Papi est poilu" il faut les formatter comme suit : "Roger est grand\r\n", "Maman est gentille\r\n" et "Papi est poilu\r\n".
Les EditBox peuvent contenir 32ko de texte donc pour avoir des vraies fonctionnalités proches de celles d'un editeur de texte (meme identiques) il existe les RichEdit qui eux sont beaucoup plus developpés et flexibles.
Pour conclure rapidement sur ces controles, vous pouvez aller un peu plus loin par vous meme en regardant un peu le type de messages qu'on peut envoyer à ce controle dans le MSDN. Vous pourrez ainsi facilement controler un grand nombre de parametre et peut etre vous exercer à tripoter les EditBox. Les messages pour ce type de controles commencent par EM_. Une petite recherche dans le msdn vous les listes tous.

2.3. Les menus.

Les menus sont importants dans une application. Ils apportent de la convivialité et sont de nos jours tellement repandus qu'il est inconcevable de ne pas savoir les utiliser. Un menu peut etre créé entièrement à partir de l'éditeur de ressources de Visual C++ (ou de tout autre EDI). Pour cela suivez la méthode habituelle pour ajouter une nouvelle ressource à votre projet et sélectionnez "Menu" en tant que nouvelle resource. Un menu standard et nu apparaitra alors. Chaque entrée du menu est appelée un "Item", de meme que chaque selection possible de vos sous menus. Chaque item va avoir une ID particuliere qui va permettre de le distinguer des autres. Cette ID ainsi que le texte associé a chaque entrée du menu peuvent etre indiqués grace à la boite "Propriété" associée à l'item. En gros le mode de fonctionnement d'un menu est le meme dans l'esprit que celui d'un GUI au complet avec ses controles standards. Vous aller simplement, à travers ce menu, fournir à l'utilisateur une interface visuelle supplémentaire proposant un certain nombre de choix possibles et il ne vous reste plus qu'à le laisser faire. Pour pouvoir répondre à chaque solicitation de l'utilisateur, nous allons ainsi devoir etre informé les differentes actions qu'il va effectuer sur le menu et réagir en conséquence. Et, une fois encore, nous allons le faire grace à des messages (ca devient habituel non ?). Ces messages vont etre directement envoyés à la Window Procedure ( cf chapitre precedent ) de la fenetre ou du dialog auquel seront attaché le menu.
Et oui, un menu ne pourra se balader tout seul comme ca dans la nature, il lui faudra un élément maitre auquel se raccrocher. Cet élément sera en general une fenetre (dialogue ou fenetre classique). Le terme attaché entend "qui sera responsable de traiter les messages résultant de l'interaction de l'utilisateur sur les items du menu".

Bon treve de blabla, passons à l'action. Plusieurs méthodes sont possibles pour rattacher un menu à une entité graphique (fenetre, boite de dialogue). Nous pouvons le spécifier dés la création de la classe dans le cas d'une fenetre (souvenez vous de la structure WNDCLASS (cf chap. 2)) ou bien charger le menu par la suite en mémoire et l'attacher à l'entité souhaitée. La manipulation d'un menu se fait à travers son handle (identificateur) qui est de type HMENU. Pour ce qui est du chargement dynamique, nous allons pouvoir le faire grace aux fonctions : LoadMenu() et SetMenu().

LoadMenu nous permet de charger en mémoire une ressource de type menu et nous renvoi un handle sur ce menu chargé en mémoire qui va nous permettre de le tripoter par la suite.

SetMenu va nous permettre d'attacher un menu à une entité graphique. Dans ce cas, c'est la WindowProc (ou DlgProc) de l'entité qui va recevoir les messages indiquant que l'utilisateur tripote le menu. Ces messages seront de type WM_COMMAND avec LOWORD(wParam) qui contiendra l'ID de l'item qui aura été selectionn, tout simplement.

Il vous est possible de modifier à volonté vos menus grace a quelques fonctions spécifiques. Vous pouvez ainsi rajouter des items, des sous menus, cocher un item de votre menu ... Ces fonctions sont AppendMenu(), InsertMenuItem(), CheckMenuItem(), etc ...
De plus, il est parfois utile de savoir qu'on peut créer des menus à la volée ("on-the-fly" en anglais) à l'aide de quelques fonctions win32. Meme si l'utilité de ce type de manipulations peu paraitre negligeable, il est tres important de savoir comment le faire dans le cas de menus contextuels par exemple (cf. ci dessous). Les fonctions CreateMenu() et CreatePopupMenu() vont nous aider dans cette tache. Comme nous pouvons nous y attendre, chacune de ces fonctions va nous renvoyer un handle sur un menu de type : HMENU. Ce handle pourra par la suite etre utilise pour rajouter des Items au menus etc ...
Pour fixer les idees, un menu dit "pop-up" est menu déroulant (ou "drop down menu") qui peut etre soit etre un sous-ensemble d'un menu déjà existant ou qui peut etre utilisé en tant que menu contextuel (cf. plus bas).





Un dernier petit détail concernant quelques points de notation pour les menus. Vous rencontrez souvent dans les menus trois petits points qui suivent le nom d'une entrée du menu, par exemple : "Save as ...". Ce n'est pas un hasard et relève d'un pseudo standard de fait qui veut que lorsqu'une entrée d'un menu provoque l'apparition d'un (ou plusieurs) autre(s) dialogue(s), le nom de l'entrée en question se voit completé de trois points de suspensions. Ainsi, dans l'exemple du dessus, "Save as ..." provoque l'ouverture d'une boite de dialogue typique permettant a l'utilisateur d'entrer le nom du fichier a sauver etc ...
Deuxième chose, il n'est pas rare (et voire systématique) de rencontrer des possibilités de raccourcis pour accéder directement à la fonctionnalite désignée par un item spécifique. Un exemple bien connu de tous est le fameux : "Ctrl^S" qui permet un acces immediat a l'entree "Save" du menu. si onregarde attentivement le nom de l'item on peut voir un : "Save". Le fait de souligner une lettre dans un menu indique que la fonctionnalité en elle meme est accessible par un raccourci quelconque. Il est facilement possible de souligner une lettre à l'aide du caractère &. Il suffit de précéder la lettre en question par un & quand on spécifie le nom de l'item dans l'éditeur de ressources. Par exemple : "&Save". Pour ce qui est de la prise en main du raccourci lui meme on verra ca plus tard (pour les curieux allez donc fouiner du cote de LoadAccelerator, TranslateAccelerator et des ressources de type Accelerator).

2.4. Les menus contextuels.

Les menus contextuels sont des menus comme les autres sauf qu'ils apparaissent en reaction à une action spécifique. Si vous ne voyez pas de quoi je parle, cliquez avec la bouton droit de votre souris sur votre browser. Et voila, normalement un menu doit apparaitre à l'endroit où vous avez cliquer.

Pour tenter d'approfondir la notion de menus contextuels, reflechissons un peu. D'apres nos connaissances, les fenetres doivent reagir a un certain nombre de solicitations de la part de l'utilisateur. Ces solicitations peuvent etre de types tres divers et Windows utilise les messages pour informer qu'il s'est passe quelque chose. Dans notre cas, nous venons de cliquer sur une fenetre (ou sur un controle quelconque ce qui est intrinssèquement la meme chose), et il vient de se passer quelque chose. Il y a du y avoir un peu d'agitation derrière et tout le monde a du s'affoler pour informer la fenetre (ou le controle) qu'on vient violement de lui cliquer dessus ! Et bien un message a été envoyé à cette fenetre. Ce message est spécifique à ce type d'action : WM_CONTEXTMENU. Il est envoyé quand l'utilisateur clique droit sur une fenetre. Il nous suffit donc de rajouter une entrée WM_CONTEXTMENU dans la DlgProc ou la WndProc qui convient (celle sur lequel l'utilisateur est censée cliquer pour avoir accès au menu contextuel).

Une fois que nous avons recu ce message, il nous faut effectivement afficher le menu. Il ne sort pas de nulle part ! Le menu que nous voulons afficher est, comme nous l'avons vu au dessus, un menu deroulant. C'est donc un "popup menu" qui sera créé par nous meme au moment du click, par exemple, avec la fonction CreatePopupMenu(). Ensuite, il faut simplement le remplir ce menu en lui ajoutant des entrées grace aux fonctions classiques de gestion de menu du type AppendMenu(), ...

Maintenant, l'affichage du menu est géré par la fonction TrackPopupMenu() qui va prendre un certain nombre de paramètres tels que la position du menu, le handle du menu à afficher, des flags de création, ... Il est a noter que l'API win32 fournit une macro bien utile quand il s'agit de récupérer les coordonnées en x et en y de l'endroit ou l'utilisateur a cliqué : GET_X_LPARAM(lParam) et GET_Y_LPARAM(lParam). Ces deux macros prennent le paramètre classique déjà vu (cf. tutoriaux précédents) des DlgProc ou bien WndProc : lParam.

Il est a signaler que la fonction TrackPopupMenu() a deux comportement possibles (qui sont définissables à travers un paramètre de flags passé à cette fonction) : bloquante ou non bloquante. J'ai deja parlé des fonctions bloquantes dans le cas des deux fonctions GetMessage() et PeekMessage(). Dans le cas bloquant, la fonction TrackPopupMenu() ne va pas retourner tant que l'utilisateur n'a rien fait. Elle attend qu'il choisisse une entrée du menu ou bien clique à coté pour l'annuler. Dans le cas non bloquant, le choix de l'utilisateur est envoye en tant que message a la fenetre sur lequel l'utilisateur a cliquer. C'est ensuite a vous de traiter correctement le message. Le comportement de cette fonction est defini par les flags TMP_RETURNCMD et TMP_NONOTIFY.

Une derniere chose pour ce qui est des menus contextuels, il y a un bug dans la fonction TrackPopupMenu(). Un bug bien connu et génant puisque le comportement actuel de cette fonction oblige la selection d'un item du menu contextuel lorsque celui la apparait. Il n'est donc pas possible d'annuler notre action. Il existe cependant un moyen de contrer ce probleme (moyen bien connu aussi) mettre un appel bidon a PostMessage() apres celui à TrackPopupMenu(). Exemple :

SetForegroundWindow(hwndDlg);
cmdID = TrackPopupMenu(handleNotreMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, xPos, yPos, 0, hwndDlg, NULL);
PostMessage(hwndDlg, WM_NULL, 0, 0);
2.5. Les Combo Box.

Nous allons maintenant nous intéresser aux combo box. Ce sont en fait des sortes de menus déroulants améliorés. Encore une fois une image vaut mieux que tous les discours :


Il est relativement simple d'utiliser les combos box et de les incorporer dans vos boites de dialogues. Il suffit de les ajouter naturellement grace a l'editeur de resource (ou bien a la main en modifiant directement le fichier de resource ".rc" si le coeur vous en dit) a l'aide du menu des controles. Bon, il y a une chose importante a savoir sans laquelle on peut facilement se faire avoir avec ce type de controle : il faut bien faire attention a definir une bonne taille pour la combo box en hauteur. Je m'explique : il est possible de specifier une taille final pour la combo box lorsque celle ci est completement deroulee. Le probleme est que par defaut cette taille est nulle, il n'est donc pas rare lorsqu'on n'a pas au moins ete confronte une fois avec le truc de se retrouver avec une combo box qui ne permet aucune selection et qui ne se deroule pas tout simplement parce qu'on a oublie de specifier une taille pour la combo box. Le pire c'est que dans le fait elle se deroule bien mais elle le fait avec une taille zero donc on ne voit rien et on passe x temps a chercher ce qui cloche dans notre source ... alors que le probleme est ailleurs. Pour specifier une telle taille maintenant il suffit de cliquer sur le petit carre contenant une fleche vers le bas a droite du controle pour passer successivement de la possibilite de lui specifier une taille en largeur a une taille en hauteur.


Configuration permettant de regler la hauteur en jouant sur le carre bleu au bas. Configuration permettant de regler la largeur en jouant sur les carres bleus sur le cote.


Pour utiliser une combo box il faut pouvoir y ajouter/enlever des elements pour que l'utilisateur puisse avoir un choix a faire ! Rien n'est moins simple, comme pour beaucoup d'autres controles nous allons utiliser des messages specifiques. Les messages specifiques aux combo box vont avoir un prefixe "CB_". Il est interessant de parcourir MSDN pour voir tous les messages lies aux combo que Windows propose. Nous allons en attendant nous interesser aux fonctionnalites simples des combo-box. Pour ajouter un element dans un combo-box il suffit d'envoyer un message CB_ADDSTRING en passant dans le parametre lParam l'adresse de la chaine de caractere a ajouter. La chaine de caractere est ajoutee a la fin du combo (a moins que votre combo-box ait une propriete lui permettant de trier son contenu). L'ami de CB_ADDSTRING est CB_DELETESTRING qui comme son nom l'indique permet d'effacer une entree de la combo. Quand vient le temps de recuperer la selection d'une combo-box, le message CB_GETCURSEL vient a notre secours. Je ne vais pas lister ici tous les messages qu'il est possible d'envoyer aux combo-box car je ne ferais que paraphraser le MSDN.
En general, une combo box est initialisee dans la partie de la DlgProc a laquelle elle est rattachee correspondant au message WM_INITDIALOG (cf. tutorial precedent).

2.6. Les list box.

Les list box sont plus ou moins apparentées, dans l'idée, aux combos box dans le sens où elles mettent en jeu des listes d'items (chaines de caracteres ou images ou les deux ) que l'on peut enlever ou retirer du controle. L'utilisation des ListBox est relativement facile quand on a vu les combo-box. Elles fonctionnent globalement pareil et il est relativement facile de les utiliser. Nous allons une fois de plus faire intervenir un certain nombre de messages qui vont nous servir pour communiquer avec le controle. Ces messages vont tous etre perfixés par un LB_. Vous pouvez donc dore et déjà aller voir un peu dans le MSDN ce que vous pouvez tirer d'une list box. Les messages ayant un nom relativement explicite vous pourrez facilement en avoir un apercu rapide. Un element dans une listbox est appele un item.

Voici une description rapide de quelques messages parmis les plus commun :

LB_ADDSTRING Ajoute une chaine de caractere dans la liste. Attention, il faut que la list box ait le style LBS_HASSTRING.
LB_DELETESTRING Efface une chaine de caractere dans la liste. Attention, il faut que la list box ait le style LBS_HASSTRING.
LB_FINDSTRING Trouve une chaine de caractere dans la liste. Attention, il faut que la list box ait le style LBS_HASSTRING
LB_GETCOUNT Retourne le nombre d'items dans la liste.
LB_GETCURSEL Retourne la selection actuelle dans la listbox (index).
LB_GETSEL Retourne l'etat d'un item (selectionne ou pas).
LB_GETTEXT Retourne le texte associe a un item. Attention la listbox doit avoir le style LBS_HASSTRING.
LB_INSERTSTRING Permet d'inserer une chaine de caractere dans la listbox. Attention la listbox doit avoir le style LBS_HASSTRING.
LB_SETCURSEL Force la selection dans la listbox.
LBN_DBLCLK Message envoye quand l'utilisateur double-click sur un item de la listbox. Ce message est recu a travers un WM_COMMAND par la fenetre mere de la listbox.



3. Les "Common Dialogs".

Windows dispose d'un ensemble de boites de dialogues standards dans ce sens que chacune repond a un besoin precis et peut etre appelee et manipulee a travers une serie d'appel de fonctions faisant parties de l'API win32. Ces boites de dialogues vous devriendrons tres vite indispensables dans la plupart de vos applications GUI. Vous les avez deja rencontre, au moins certaines d'entres elles. Ainsi, a chaque fois que vous faites un "Save As ..." dans l'un de vos menu, une boite de dialogue type apparait. Il s'agit d'une des boites de dialogue dite "Commong Dialog", idem pour la boite de dialogue de configuration d'imprimante, etc ...

Ouverture/fermeture de fichiers.

Demander le lancement de la boite de dialogue permettant la selection d'un (ou plusieurs) fichier(s) a ouvrir ou a sauvegarder se fait grace aux fonction de l'API Win32 :
GetOpenFileName() et GetSaveFileName(). Il faut passer a ces deux fonction une structure de type OPENFILENAME qui va decrire le comportement du dialogue et le type de services qu'on veut offrir a l'utilisateur. Il va ainsi etre possible de proposer un filtre sur les fichiers a ouvrir/sauver au niveau du type d'extension attendue, de configurer l'apparence et les possibilites de la boite de dialogue, etc ... Voici la description de quelques champs de la structure que vous pourrez etre susceptibles de rencontrer le plus souvent :

lStructSize Correspond a la taille de la structure en octets.
hwndOwner Handle de la fenetre dont ce dialogue depend.
lpstrFilter Filtre sur le type de fichier accepté par l'application. Nous allons ainsi pouvoir accepter par exemple que les fichiers texte (".txt") et le dire explicitement dans le dialogue (commentaire : "Fichier texte"). Ce champ est une chaine de caractere formattée d'une manière particulière permettant d'entrer un ou (plusieurs) filtre(s) associé(s) à une (ou plusieurs) extension(s). Un filtre, dans ce contexte précis, correspond à une description du type de fichier suivie d'une série de chaines de caractères décrivant les extensions de fichiers associées à la description précédente. Par exemple, si jamais nous ne voulons accepter que les fichiers texte avec les extensions ".txt" ou ".diz" nous allons spécifier : "Text files\0*.diz;*.txt\0\0" Comme vous le voyez il est possible de mettre plusieurs extensions en les séparant de ";". Il est aussi commun de mettre la liste des extensions de fichiers autorisées entre parenthèses dans la description du type de fichier : "Text files (*.txt, *.diz)\0*.diz;*.txt\0\0". Il est de plus facile de permettre plusieurs types de fichiers, simplement en les chainant : "Text files\0*.diz;*.txt\0Source files\0*.cpp;*.h\0\0". Nous acceptons donc dans ce dernier exemple, les fichiers textes (".txt" ou bien ".diz") et les fichiers sources (".cpp" ou ".h").
lpstrFile Un pointeur sur un tableau de caractere suscpetible de recevoir le nom du fichier (chemin complet+ nom de fichier + extension ).
nMaxFile Taille en octets du tableau ci-dessus.
lpstrFileTitle Idem que lpstrFile mais contient le nom du fichier ainsi que son extension.
nMaxFileTitle La taille en octets du tableau ci-dessus.
Flags Un ensemble de flags que l'on peut combiner en semble grace à un simple ou logique ("|") et qui vont déterminer le comportement de la boite de dialogue (save, load file, style du dialogue, ... ).


Donc pour résumer, les deux fonctions GetOpenFileName() et GetSaveFileName() vont lancer une boite de dialogue du meme type mais ayant un comportement différent et des caracteristiques dépendant de vos choix dans la structure OPENFILENAME.

Voici ce que ca donne :





Choix d'une couleur.

La fonction ChooseColor() va nous permettre d'afficher une boite de dialogue permettant le choix d'une couleur par l'utilisateur. Je ne vais pas m'étendre là encore sur la signification de chaque parametre mais voici un exemple d'utilisation.

#include <windows.h>

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	CHOOSECOLOR cc;
	COLORREF ar[16];
	
	ZeroMemory ( &cc, sizeof(cc) );
	
	cc.lStructSize = sizeof(cc);
	cc.hwndOwner = NULL;
	cc.Flags = CC_ANYCOLOR;
	cc.lpCustColors = &ar[0];
	
	ChooseColor( &cc);
}
NOTE: une petite remarque pour vous signaler l'existance de la macro ZeroMemory qui comme son nom l'indique nous est fournie par l'API win32 pour mettre a zero une zone de memoire particuliere.

Choix d'une imprimante.

La fonction PrintDlg() va nous permettre d'afficher un dialog de configuration d'impression. Je ne vais pas detailler tous les parametres mais simplement vous donner un exemple qui fonctionne :

#include <windows.h>

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	// structure de base decrivant notre boite de dialogue
	PRINTDLG p;
	
	ZeroMemory( &p, sizeof(p) );
	
	p.lStructSize = sizeof(PRINTDLG);
	p.hwndOwner = NULL;
	p.Flags = PD_PRINTSETUP | PD_RETURNDC;
	
	PrintDlg( &p );	
}
NOTE: une petite remarque pour vous signaler l'existance de la macro ZeroMemory qui comme son nom l'indique nous est fournie par l'API win32 pour mettre a zero une zone de memoire particuliere.

Il existe d'autres CommonDialog qui fonctionnent sur le meme principe. C'est a vous de les decouvrir (cf. MSDN encore une fois ).



4. Pour conclure sur les dialogues : modale ou pas modale ?.

Avant de vous quitter j'aimerais revenir sur une chose qui me semble importante : la notion de boite de dialogue modale. Je vais pas trop m'étendre dessus vu que le tutorial s'est pas mal allongé par rapport à ce que je voulais qu'il soit au départ ( à force de vouloir y rajouter des détails et encores des remarques :). Cette notion se retrouve aussi quand on utilise les MFCs donc au moins à ce niveau là vous ne serez pas completement dans le flou.
Alors donc qu'est ce qu'une boite de dialogue modale ?
Il s'agit d'une boite de dialogue bloquante. En fait c'est pas la boite de dialogue en elle meme qui est bloquante mais l'appel a la fonction permettant de lancer la boite de dialogue. Pour avoir des précisions sur la notion de boite de dialogue bloquante réferez vous aux tutoriaux précédents. Pour en avoir un exemple simple cliquez dans le menu de votre navigateur internet dans "Fichier">"Enregistrer sous ...". Une boite de dialogue que vous etes maintenant censé connaitre (cf boite de dialogue commune au dessus) apparaitra. Maintenant, essayez de faire revenir au premier plan l'interface de votre navigateur qui doit etre maintenant juste sous le dialogue de sauvegarde de fichier. Et bien vous ne pouvez pas. Voila, une boite de dialogue modale. Elle va empecher l'acces a tout le reste de votre GUI (Graphic User Interface = "Interface Utilisateur Graphique") et bloquer en attente d'une réponse. Vous vous doutez bien qu'une boite de dialogue non modale est tout le contraire. Vous aller pouvoir passer allegrement de votre boite de dialogue au reste de vos éléments de GUI. On appel ce type de dialogue "modeless" en anglais.
Pour créer une boite de dialogue d'un type ou d'un autre, il faut simplement choisir entre deux fonctions de l'API Win32 : CreateDialog() ou bien DialogBox() que nous avons deja vu. Ces deux fonctions prennent des parametres quasi-identiques je n'ai donc pas besoin de m'étendre dessus. CreateDialog() permet de créer une boite de dialogue modeless (non modale donc) alors que vous l'aurez deviner DialogBox() est une macro qui permet de creer des boites de dialogues modales.

Voila pour ce tutorial, j'espere encore une fois qu'il aura ete aussi clair que possible et dans le cas contraire n'hesitez pas a me le faire savoir. Je recois regulierement des emails et je m'efforce d'y repondre au plus vite et du mieux que je peux. Ca fait toujours plaisir de recevoir 2 ou 3 mots, ca motive pour la suite quoi. Bref, maintenant c'est a vous de jouer ... a vos lignes de code !




Liens interessants.

MSDN consultable sur le net : http://msdn.microsoft.com/library/default.asp
VisualC++ 6 service pack 5 : http://msdn.microsoft.com/vstudio/sp/vs6sp5/vcfixes.asp
DevC++ (EDI sous Windows qui utilise mingw comme compilateur) : http://www.bloodshed.net/devcpp.html

--
Document ecrit par ABREU Alexandre : wiss1976@yahoo.fr
Libre reproduction et diffusion autorisée - modifications interdites sans autorisation de l'auteur.

Précédent Suivant