IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

API Windows en C

Sous-classement de fenêtres

Sous-classement de fenêtres. ♪

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. 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 message de notification qui leur est associé. 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 nous ne désirons pas (pour l'exemple).

Image non disponible

II. Préparation de l'exemple:

Après avoir créé le contrôle d'édition, nous changerons son curseur contre celui en forme de flèche. Ceci juste pour montrer que l'on ne peut pas l'éditer.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
    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 la 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.

III. Mise en œuvre

Accéder à la procédure de fenêtre du contrôle ne sera pas suffisant. On ne pourra en obtenir qu’un pointeur. Il ne pourra donc servir qu'à l'appeler. Nous devons donc en créer une nouvelle.

 
Sélectionnez
1.
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.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
#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 veut implémenter se font bien sûr dans la nouvelle procédure de fenêtre du contrôle :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
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.

IV. Code complet

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
#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++.

À vos PC.

CGi

Retour au sommaire.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Copyright © 2005 CGi. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.