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


API Windows en C

2 - Contrôles et Messages.

Par CGi

Le 30 mai 2005




Introduction :

Dans ce chapitre, nous allons revenir sur le traitement des messages.
Nous allons aussi créer un contrôle enfant que nous allons mettre sur la fenêtre principale.
Ce contrôle sera un contrôle d'édition multi lignes. Il devra se positionner sur toute la surface client de la fenêtre principale (on appelle surface client d'une fenêtre toute sa partie intérieure, c'est-à-dire la fenêtre sans sa bordure et sa barre de titre).


Création d'un contrôle :

Comme nous l'avons dit au chapitre précédent un contrôle est une fenêtre. Nous allons donc utiliser comme pour la fenêtre principale la fonction CreateWindow pour le créer.


     HWND hEdit;
     hEdit =CreateWindow("edit", "Texte",
              WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL,
                                           0, 0, 0, 0, hwnd, NULL, hinst, NULL);

Pour les contrôles, les classes de fenêtres sont globales et définies par Windows. Celle du contrôle d'édition s'appelle : "EDIT". Nous la mettrons donc comme premier paramètre de CreateWindow.
Son deuxième paramètre attend un pointeur sur une chaîne de caractères au cas ou vous désirez qu'il contienne du texte dès sa création.
Le troisième attend les identificateurs de style. Ils sont ici complètement différents de ce qu'on avait mis pour la fenêtre principale :
WS_VISIBLE rend la fenêtre visible dés sa création.
WS_CHILD en fait un contrôle enfant. C'est obligatoire si l'on veut qu'il soit à l'intérieur de notre fenêtre.
ES_MULTILINE multi lignes si on veut avoir la possibilité de saisir plusieurs lignes.
ES_WANTRETURN autorise le retour à la ligne automatique.
WS_VSCROLL pour lui mettre un ascenseur vertical.
(Les identificateurs de style étant très nombreux, je vous propose de consulter l'aide Win32 API CreateWindow, ou CreateWindowEx qui permet des styles supplémentaires).
Les quatre paramètres suivants sont comme pour la fenêtre principale, sa position et ses dimensions. Dans le code complet de l'exemple, elles sont toutes mises à zéro car le contrôle sera redimensionné automatiquement à chaque changement de dimensions de la fenêtre principale (voir plus loin dans ce document).
Le paramètre suivant est le handle de la fenêtre principale car elle en est le parent.
Et comme pour la fenêtre principale le handle d'instance de l'application pour l'avant dernier paramètre.
Dans le code de l'exemple, pour des raisons de simplicité, j'ai créé une variable globale pour le handle d'instance que j'ai initialisé dans la fonction WinMain.


Les messages :

Nous avons dit que notre contrôle d'édition devait se redimensionner pour occuper la surface client de la fenêtre principale. Mais comment savoir que les dimensions de la fenêtre principale ont changé ? Par l'intermédiaire d'un message ! Si un utilisateur a changé les dimensions de la fenêtre, Windows va envoyer un message à cette fenêtre pour l'en informer. Dans ce cas précis le message est WM_SIZE. C'est à nous de traiter ce message dans la procédure de fenêtre :

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static HWND hEdit;
    
    switch (uMsg)
    {
        case WM_CREATE:
            hEdit =CreateWindow("edit", "Texte",
              WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL,
                                           0, 0, 0, 0, hwnd, NULL, hinst, NULL);
            return 0;

        case WM_SIZE:
            MoveWindow(hEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
            return 0;

        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;

        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

Comme vous pouvez le voir dans l'exemple nous créons le contrôle d'édition à l'arrivée du message WM_CREATE, message envoyé par Windows quand la création de la fenêtre principale est terminée, mais pas encore visible. A la réception du message WM_SIZE, nous récupérons les dimensions de la surface client de la fenêtre dans le paramètre lParam joint au message. La largeur étant dans son mot de poids faible et la hauteur dans son mot de poids fort. Nous les extrayons à l'aide des macros LOWORD et HIWORD. Et nous affecterons ces dimensions au contrôle d'édition à l'aide de la fonction MoveWindow (son dernier paramètre à TRUE informe Windows qu'il doit redessiner le contrôle après l'appel de la fonction).
Son premier paramètre étant le handle du contrôle d'édition, car c'est lui dont on change les dimensions.
Il est évident que l'on ne va pas passer tous les messages en revue, vous pouvez pour cela consulter l'aide sur L'API Win32. Cet exemple vous donne déjà une idée de la manière dont on intercepte les événements dans Windows. Nous aurons l'occasion de voir et revoir les messages dans les chapitres suivants. Il sont omniprésent dans Windows. Le moindre événement qui survient et c'est un message qui est envoyé. Il est donc important d'être bien documenté, notament sur les divers messages existants. Et ils sont nombreux.
Comme dit au chapitre précédent, les messages non traités doivent l'être par la fonction DefWindowProc. C'est une procédure de fenêtre interne qui traite les messages afin de faire le minimum vital pour la fenêtre. Ne serait ce que simplement l'afficher.

Structure MSG :

typedef struct tagMSG {     
    HWND   hwnd;	// Handle de la fenêtre de destination. 
    UINT   message;     // Le message proprement dit.
    WPARAM wParam;      // Paramètre dépendant du message.
    LPARAM lParam;      // Paramètre dépendant du message.
    DWORD  time;        // Heure ou il a été posté.
    POINT  pt;          // Coordonnées du curseur au moment ou il a été posté.
} MSG; 



Code complet :

#include <windows.h>

HINSTANCE hinst;

LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);

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",
              WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL,
                                           0, 0, 0, 0, hwnd, NULL, hinst, NULL);
            return 0;

        case WM_SIZE:
            MoveWindow(hEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
            return 0;

        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;

        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

Dans le code de cet exemple j'ai mis le pinceau à NULL (wc.hbrBackground = NULL) dans la classe de fenêtre de la fenêtre principale, sinon un il y a scintillement désagréable sur l'ascenseur du contrôle d'édition lors des redimensionnements.

Ce code a été testé sous VC++, CodeBlocks(Mingw), C++ Builder, DevC++.



A vos PC.

CGi

Avec la contribution de Bestiol pour la relecture.



Sommaire



C/C++
  Les pointeurs du C/C++.   Les listes chaînées.             Liste simple.             Liste triée.             Liste double.   Les arbres.   Les tas.   Le C orienté objets ?

  1 - La fenêtre principale.   2 - Contrôles et messages.   3 - Les commandes.   4 - Dialogue std.   5 - Contexte de périph.   6 - Dessiner.   7 - Les ressources.   8 - Dialogue perso.   9 - Dialogue comm.   10 - Les accélérateurs.

Assembleur
  Assembleur sous Visual C++.

C++ BUILDER
  Trucs et astuces.   Composant.   TRichEdit.   TDrawGrid.   Application MDI.   TThread.   wxWidgets.   Style Win XP.

  Première application.   Construire un menu.   Dessiner.   Sisers, Timers...   Dialogues standards.   Dialogues perso.

DotNet
  Composant C# Builder.   Contrôle WinForm.   Application MDI.

Java
  Applet java.





Copyright 2002-2020 CGi - Tous droits réservés CGi. Toutes reproduction, utilisation ou diffusion de ce document par quelque moyen que ce soit autre que pour un usage personnel doit faire l'objet d'une autorisation écrite de la part de l'auteur, propriétaire des droits intellectuels.
Les codes sources de ce document sont fournis en l'état. L'utilisateur les utilise à ses risques et périls, sans garantie d'aucune sorte de la part de l'auteur. L'auteur n'est responsable d'aucun dommage subi par l'utilisateur pouvant résulter de l'utilisation ou de la distribution des codes sources de ce document.
De la même façon, l'auteur n'est en aucun cas responsable d'une quelconque perte de revenus ou de profits, ou de données, ou de tous dommages directs ou indirects, susceptibles de survenir du fait de l'utilisation des codes sources de ce document, quand bien même l'auteur aurait été averti de la possibilité de tels dommages. L'utilisation des codes sources de ce document vaut acceptation par l'utilisateur des termes de la licence ci-dessus.