Tutorial d'initiation A la programmation avec l'API Windows
Tutorial d'initiation a la programmation Windows avec Microsoft Visual C++
Chapitre 1Les bases d'un programme Windows2. Création d'une fenêtre
Cours théorique :
Dans la première partie de ce chapitre, nous avons vu comment créer une boite de dialogue. La création d'une boite de dialogue grâce à la fonction CreateDialog() est relativement simple puisqu'une grande partie du travail est effectué par CreateDialog().
Nous allons donc voir maintenant comment créer une fenêtre. Cette fenêtre pourra être personnalisée et ne réferrera à aucune resource. Notre programme n'utilisera donc pas de resources.
Comme nous avons pu le voir dans la partie précédente, le programme n'intervient en aucun cas dans le dessin de la fenêtre (barre de titre, menu...). Le programme n'est responsable que du redessinement de la zone client de la fenêtre. Comme il existe plusieurs types de fenêtre (avec un menu, sans menu, pouvant être minimisée ou pas...) il est nécessaire que de créer un 'protoype de fenêtre'. Ce prototype est aussi appelé classe de la fenêtre. C'est sur ce prototype que Windows se basera pour créer la fenêtre.
Une fois le prototype de fenêtre créé, nous demanderons à Windows de créer une fenêtre suivant ce prototype. La fenêtre créée devra elle aussi disposer d'une procédure permettant de traiter les messages qu'elle reçoit. Cette procédure est très similaire à celle gérant la boite de dialogue de la partie précédante. Elle ne traite cependant pas exactement les messages de la même manière.
Projet N°2 :
- Objectif : créer une fenêtre sans utiliser de resource et une procédure permettant sa gestion.
- Réalisation : la fenêtre sera créée sans utiliser de resource et sa procédure traitera les messages les plus simples.
Télécharger le projet ici.
- Le projet pas à pas :
Il s'agit tout d'abord de créer un projet dans Microsoft Visual C++. Le projet sera créé de la même manière que dans la partie précédente, mais sans y ajouter de Ressource Script.
Le point d'entrée WinMain() est un standard à toute application Windows, ce programme débutera donc de la même manière que le précédant.
#include <Windows.h>
LRESULT CALLBACK MainProc(HWND Dlg,UINT message,WPARAM wParam,LPARAM lParam);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
Il faut mintenant créer une nouvelle classe de fenêtre. Cette classe est créée au moyen de la fonction RegisterClassEx(). La création de cette classe paut paraître fastidieuse et comprend un grand nombre de paramètres. nous n'utiliserons pas tous les paramètres, donc ne vous effrayez pas si vous ne comprenez pas totalement l'utilité de chaqun d'eux.
WNDCLASSEX principale; principale.cbSize=sizeof(WNDCLASSEX); principale.style=CS_HREDRAW|CS_VREDRAW; principale.lpfnWndProc=MainProc; principale.cbClsExtra=0; principale.cbWndExtra=0; principale.hInstance=hInstance; principale.hIcon=LoadIcon(NULL,IDI_APPLICATION); principale.hCursor=LoadCursor(NULL,IDC_ARROW); principale.hbrBackground=reinterpret_cast<HBRUSH>(COLOR_WINDOW+1); principale.lpszMenuName=NULL; principale.lpszClassName="std"; principale.hIconSm=LoadIcon(NULL,IDI_APPLICATION); RegisterClassEx(&principale);
principale.style=CS_HREDRAW|CS_VREDRAW indique que notre fenêtre devra être redessinée en cas de redimentionnement horizontal ou vertical. Nous indiquons ensuite quelle procédure sera chargée de gérer la fenêtre. L'instance de notre application est elle aussi passée en paramètre. Les curseurs ou icones de notre fenêtre sont ceux par défaut de Windows. La fenêtre n'as pas de menu, la couleur de fond est celle de Windows par défaut. Le nom de la classe de la fenêtre 'std' est un choix personnel. Il n'a d'importance que pour nous. Une fois la structure remplie, un appel à RegisterClassEx() demande à Windows de mémoriser la classe.
Maintenant que nous disposons de notre classe de fenêtre, il ne reste plus qu'a la créer grâce à la fonction CreateWindowEx().
HWND hWnd; hWnd=CreateWindowEx( WS_EX_CLIENTEDGE, "std", "Notre fenêtre", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL );
ShowWindow(hWnd,SW_SHOW);
La réception des messages se fait exactement de la même manière que dans le projet précédent.
MSG msg; while(GetMessage(&msg,NULL,0,0)==TRUE) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; }
La définition de la procédure de cette fenêtre est la même que dans le programme précédent. Mais son fonctionnement interne est différent.
Tout d'abord, cette fenêtre ne contient pas de bouton. Sa fermeture se fera lors d'un clic sur la 'croix'. Les messages non traités sont passés à DefWindowProc(). Les messages traités seront WM_PAINT et WM_DESTROY. WM_PAINT indique que nous devons redessiner la zone client. Ici le traitement de ce message ne fera rien et pourrait être ignoré. Il est inclu dans le seul but de comprendre le mécanisme de redessinement d'une fenêtre. Le message WM_DESTROY indique que la fenêtre est en train d'être détruite (probablement suite au clic sur la 'croix'). Le fermeture de la fenêtre ne signifie pas forcément l'arret de l'application. Mais comme dans ce cas notre application n'est formée que d'une fenêtre, nous demanderons à terminer l'application dans ce cas en postant un message WM_QUIT.
LRESULT CALLBACK MainProc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT paintst; switch (mes) { case WM_PAINT: hDC=BeginPaint(hWnd,&paintst); EndPaint(hWnd,&paintst); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProc(hWnd, mes, wParam, lParam); } }
Le traitement du message WM_PAINT peut vous paraitre étrange. En effet, pourquoi effectuer un BeginPaint() et un EndPaint() alors que nous ne dessinons rien. La raison est très simple. A partir du moment ou nous décidons de traiter ce message, nous devons assurer un traitement minimum par la suite de ces deux fonction, même si rien n'est dessiné.
|