Introduction :
Dans une application, vous traitez les messages des fenêtres ordinaires ou
des boîtes de dialogue. Les contrôles leur envoient des messages de notification
pour signaler un événement propre à eux mêmes. Malheureusement, tous les
événements de ces contrôles n'ont pas de messages de notification qui leurs sont associés.
Si vous voulez tout de même traiter un de ces événements, une seule solution,
accéder à la procédure de fenêtre du contrôle.
Pour cet exemple, nous reprendrons l'exemple du chapitre 2
"Contrôles et Messages".
Nous mettrons le contrôle d'édition en lecture seule, mais pas en lui donnant
le style "lecture seule" qui lui donnerait un fond gris.
Ce que ne nous ne désirons pas (pour l'exemple).
Préparation de l'exemple:
Après avoir créé le contrôle d'édition nous changerons son curseur par celui
en forme de flèche. Ceci juste pour montrer visuellement que l'on ne peut pas l'éditer.
static HWND hEdit;
switch (uMsg)
{
case WM_CREATE:
hEdit =CreateWindow("edit", "Texte non modifiable.\r\nVous ne pouvez \
que le lire.\r\nMais il garde la couleur du fond d'un contrôle d'édition actif.",
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL,
0, 0, 0, 0, hwnd, NULL, hinst, NULL);
SetClassLong(hEdit, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));
Cette action étant réalisée en le changeant dans la classe de fenêtre du contrôle.
Ceci sera réalisé à l'aide de la fonction SetClassLong. Elle permet
de modifier des éléments d'une classe de fenêtre déjà créée.
Mise en oeuvre:
Accéder à la procédure de fenêtre du contrôle ne sera pas suffisant.
On ne pourra en obtenir que seulement un pointeur.
Il ne pourra donc servir qu'à l'appeler.
Nous devons donc en créer une nouvelle.
LRESULT APIENTRY EditProc(HWND, UINT, WPARAM, LPARAM);
Ensuite, on affectera la nouvelle procédure de fenêtre au contrôle d'édition
avec la fonction SetWindowLong, qui de plus nous retourne l'adresse
de l'ancienne procédure de fenêtre.
#ifdef STRICT
WNDPROC wpOrigEditProc ;
#else
FARPROC wpOrigEditProc ;
#endif
/*...
... */
wpOrigEditProc = (PVOID)SetWindowLong(hEdit,
GWL_WNDPROC, (LONG)EditProc);
SetWindowLong permet de modifier les propriétés d'une fenêtre
comme son style par exemple.
Le pointeur sur l'ancienne procédure de fenêtre nous est nécessaire pour traiter
les messages par défaut du contrôle.
Les traitements que l'on veux implémenter se font bien sûr dans la nouvelle
procédure de fenêtre du contrôle :
LRESULT APIENTRY EditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_SETFOCUS || uMsg == WM_CONTEXTMENU || uMsg == WM_CHAR ||
uMsg == WM_KEYDOWN)
return 0;
return CallWindowProc(wpOrigEditProc, hwnd, uMsg, wParam, lParam);
}
Dans cette nouvelle procédure, on doit comme déjà dit, appeler l'ancienne procédure afin
d'effectuer les actions par défaut du contrôle, ne serait-ce que de se dessiner
par exemple. C'est le rôle de la fonction CallWindowProc qui reçoit bien sûr
le pointeur sur l'ancienne procédure de fenêtre et les paramètres du message.
Dans notre exemple on bloquera les messages,
WM_SETFOCUS (pour qu'il ne puisse pas prendre le focus),
WM_CONTEXTMENU (pour ne pas ouvrir son menu contextuel),
WM_KEYDOWN et WM_CHAR (pour qu'il ne puisse pas recevoir des commandes ou
des caractères depuis le clavier).
Ces messages ne seront donc pas envoyés à la procédure de fenêtre d'origine.
Ceci afin d'en faire un contrôle d'édition en lecture seule qui n'est pas gris.
Code complet :
#include <windows.h>
#ifdef STRICT
WNDPROC wpOrigEditProc ;
#else
FARPROC wpOrigEditProc ;
#endif
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT APIENTRY EditProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hinst;
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS wc;
hinst = hinstance;
wc.style = 0 ;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "MaWinClass";
if(!RegisterClass(&wc)) return FALSE;
hwnd = CreateWindow("MaWinClass", "Titre", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 300,
NULL, NULL, hinstance, NULL);
if (!hwnd) return FALSE;
ShowWindow(hwnd, nCmdShow);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
/******************************************************************************/
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hEdit;
switch (uMsg)
{
case WM_CREATE:
hEdit =CreateWindow("edit", "Texte non modifiable.\r\nVous ne pouvez \
que le lire.\r\nMais il garde la couleur du fond d'un contrôle d'édition actif.",
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL,
0, 0, 0, 0, hwnd, NULL, hinst, NULL);
SetClassLong(hEdit, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));
wpOrigEditProc = (PVOID)SetWindowLong(hEdit,
GWL_WNDPROC, (LONG)EditProc);
return 0;
case WM_SIZE:
MoveWindow(hEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
return 0;
case WM_DESTROY:
SetWindowLong(hEdit, GWL_WNDPROC, (LONG)wpOrigEditProc);
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
/******************************************************************************/
LRESULT APIENTRY EditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_SETFOCUS || uMsg == WM_CONTEXTMENU || uMsg == WM_CHAR ||
uMsg == WM_KEYDOWN)
return 0;
return CallWindowProc(wpOrigEditProc, hwnd, uMsg, wParam, lParam);
}
J'ai testé les compilations avec C++ Builder et DevC++.
A vos PC.
CGi
Avec la contribution de pharaonix pour la relecture.
|