Utilisation des fenêtres

Les exemples de cette section décrivent comment effectuer les tâches suivantes :

Créer une fenêtre principale

La première fenêtre qu’une application crée est généralement la fenêtre principale. Vous créez la fenêtre principale en utilisant la fonction CreateWindowEx, en spécifiant la classe de fenêtre, le nom de la fenêtre, les styles de fenêtre, la taille, la position, le handle de menu, le handle d’instance et les données de création. Une fenêtre principale appartient à une classe de fenêtre définie par l’application, vous devez donc enregistrer la classe de fenêtre et fournir une procédure de fenêtre pour la classe avant de créer la fenêtre principale.

La plupart des applications utilisent généralement le style WS_OVERLAPPEDWINDOW pour créer la fenêtre principale. Ce style donne à la fenêtre une barre de titre, un menu de fenêtre, une bordure de dimensionnement, et des boutons de minimisation et de maximisation. La fonction CreateWindowEx retourne un handle qui identifie de manière unique la fenêtre.

L’exemple suivant crée une fenêtre principale appartenant à une classe de fenêtre définie par l’application. Le nom de la fenêtre, Fenêtre principale, apparaîtra dans la barre de titre de la fenêtre. En combinant les styles WS_VSCROLL et WS_HSCROLL avec le style WS_OVERLAPPEDWINDOW, l’application crée une fenêtre principale avec des barres de défilement horizontales et verticales en plus des composants fournis par le style WS_OVERLAPPEDWINDOW. Les quatre occurrences de la constante CW_USEDEFAULT définissent la taille et la position initiales de la fenêtre aux valeurs par défaut définies par le système. En spécifiant NULL au lieu d’un handle de menu, la fenêtre aura le menu défini pour la classe de fenêtre.

HINSTANCE hinst; 
HWND hwndMain; 
 
// Create the main window. 
 
hwndMain = CreateWindowEx( 
    0,                      // no extended styles           
    "MainWClass",           // class name                   
    "Main Window",          // window name                  
    WS_OVERLAPPEDWINDOW |   // overlapped window            
             WS_HSCROLL |   // horizontal scroll bar        
             WS_VSCROLL,    // vertical scroll bar          
    CW_USEDEFAULT,          // default horizontal position  
    CW_USEDEFAULT,          // default vertical position    
    CW_USEDEFAULT,          // default width                
    CW_USEDEFAULT,          // default height               
    (HWND) NULL,            // no parent or owner window    
    (HMENU) NULL,           // class menu used              
    hinst,                  // instance handle              
    NULL);                  // no window creation data      
 
if (!hwndMain) 
    return FALSE; 
 
// Show the window using the flag specified by the program 
// that started the application, and send the application 
// a WM_PAINT message. 
 
ShowWindow(hwndMain, SW_SHOWDEFAULT); 
UpdateWindow(hwndMain); 

Notez que l’exemple précédent appelle la fonction ShowWindow après avoir créé la fenêtre principale. Cette opération est effectuée parce que le système n’affiche pas automatiquement la fenêtre principale après sa création. En passant l’indicateur SW_SHOWDEFAULT sur ShowWindow, l’application permet au programme qui a démarré l’application de définir l’état d’affichage initial de la fenêtre principale. La fonction UpdateWindow envoie la fenêtre son premier message WM_PAINT .

Créer, énumérer et dimensionner des fenêtres enfants

Vous pouvez diviser la zone client d’une fenêtre en différentes zones fonctionnelles en utilisant des fenêtres enfants. La création d’une fenêtre enfant est similaire à la création d’une fenêtre principale - vous utilisez la fonction CreateWindowEx. Pour créer une fenêtre d’une classe de fenêtre définie par l’application, vous devez enregistrer la classe de fenêtre et fournir une procédure de fenêtre avant de créer la fenêtre enfant. Vous devez donner à la fenêtre enfant le style WS_CHILD et spécifier une fenêtre parent pour la fenêtre enfant lors de sa création.

L’exemple suivant divise la zone cliente de la fenêtre principale d’une application en trois zones fonctionnelles en créant trois fenêtres enfants de taille égale. Chaque fenêtre enfant a la même hauteur que la zone cliente de la fenêtre principale, mais chacune a un tiers de sa largeur. La fenêtre principale crée les fenêtres enfants en réponse au message WM_CREATE, que la fenêtre principale reçoit pendant son propre processus de création de fenêtre. Comme chaque fenêtre enfant a le style WS_BORDER, chacune a une fine bordure. De plus, comme le style WS_VISIBLE n’est pas spécifié, chaque fenêtre enfant est initialement cachée. Notez également que chaque fenêtre enfant se voit attribuer un identifiant de fenêtre enfant.

La fenêtre principale dimensionne et positionne les fenêtres enfants en réponse au message WM_SIZE, que la fenêtre principale reçoit lorsque sa taille change. En réponse à WM_SIZE, la fenêtre principale récupère les dimensions de sa zone cliente en utilisant la fonction GetClientRect puis passe les dimensions à la fonction EnumChildWindows. EnumChildWindows transmet le handle à chaque fenêtre enfant, à son tour, à la fonction de rappel définie par l’application EnumChildProc. Cette fonction dimensionne et positionne chaque fenêtre enfant en appelant la fonction MoveWindow ; la taille et la position sont basées sur les dimensions de la zone cliente de la fenêtre principale et l’identifiant de la fenêtre enfant. Ensuite, EnumChildProc appelle la fonction ShowWindow pour rendre la fenêtre visible.

#define ID_FIRSTCHILD  100 
#define ID_SECONDCHILD 101 
#define ID_THIRDCHILD  102 
 
LONG APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    RECT rcClient; 
    int i; 
 
    switch(uMsg) 
    { 
        case WM_CREATE: // creating main window  
 
            // Create three invisible child windows. 

            for (i = 0; i < 3; i++) 
            { 
                CreateWindowEx(0, 
                               "ChildWClass", 
                               (LPCTSTR) NULL, 
                               WS_CHILD | WS_BORDER, 
                               0,0,0,0, 
                               hwnd, 
                               (HMENU) (int) (ID_FIRSTCHILD + i), 
                               hinst, 
                               NULL); 
            }
 
            return 0; 
 
        case WM_SIZE:   // main window changed size 
 
            // Get the dimensions of the main window's client 
            // area, and enumerate the child windows. Pass the 
            // dimensions to the child windows during enumeration. 
 
            GetClientRect(hwnd, &rcClient); 
            EnumChildWindows(hwnd, EnumChildProc, (LPARAM) &rcClient); 
            return 0; 

        // Process other messages. 
    } 
    return DefWindowProc(hwnd, uMsg, wParam, lParam); 
} 
 
BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam) 
{ 
    LPRECT rcParent; 
    int i, idChild; 
 
    // Retrieve the child-window identifier. Use it to set the 
    // position of the child window. 
 
    idChild = GetWindowLong(hwndChild, GWL_ID); 
 
    if (idChild == ID_FIRSTCHILD) 
        i = 0; 
    else if (idChild == ID_SECONDCHILD) 
        i = 1; 
    else 
        i = 2; 
 
    // Size and position the child window.  
 
    rcParent = (LPRECT) lParam; 
    MoveWindow(hwndChild, 
               (rcParent->right / 3) * i, 
               0, 
               rcParent->right / 3, 
               rcParent->bottom, 
               TRUE); 
 
    // Make sure the child window is visible. 
 
    ShowWindow(hwndChild, SW_SHOW); 
 
    return TRUE;
}

Détruire une fenêtre

Vous pouvez utiliser la fonction DestroyWindow pour détruire une fenêtre. En règle générale, une application envoie le message WM_CLOSE avant de détruire une fenêtre, donnant à la fenêtre l’opportunité de demander une confirmation à l’utilisateur avant que la fenêtre ne soit détruite. Une fenêtre qui inclut un menu de fenêtre reçoit automatiquement le message WM_CLOSE lorsque l’utilisateur clique sur Fermer depuis le menu de la fenêtre. Si l’utilisateur confirme que la fenêtre doit être détruite, l’application appelle DestroyWindow. Le système envoie le message WM_DESTROY à la fenêtre après l’avoir retirée de l’écran. En réponse à WM_DESTROY, la fenêtre sauvegarde ses données et libère toutes les ressources qu’elle a allouées. Une fenêtre principale conclut son traitement de WM_DESTROY en appelant la fonction PostQuitMessage pour quitter l’application.

L’exemple suivant montre comment demander une confirmation de l’utilisateur avant de détruire une fenêtre. En réponse à WM_CLOSE, une boîte de dialogue est affichée contenant les boutons Oui, Non, et Annuler. Si l’utilisateur clique sur Oui, DestroyWindow est appelé ; sinon, la fenêtre n’est pas détruite. Comme l’application gère le message WM_CLOSE, 0 est retourné dans tous les cas. Comme la fenêtre détruite est une fenêtre principale, l’exemple appelle PostQuitMessage en réponse à WM_DESTROY.

case WM_CLOSE: 
 
    // Create the message box. If the user clicks 
    // the Yes button, destroy the main window. 
 
    if (MessageBox(hwnd, szConfirm, szAppName, MB_YESNOCANCEL) == IDYES) 
        DestroyWindow(hwndMain); 
    return 0; 
 
case WM_DESTROY: 
 
    // Post the WM_QUIT message to 
    // quit the application terminate. 
 
    PostQuitMessage(0); 
    return 0;

Utiliser des fenêtres superposées

Pour faire apparaître une boîte de dialogue comme une fenêtre translucide, créez d’abord la dialogue comme d’habitude. Ensuite, sur WM_INITDIALOG, définissez le bit superposé du style étendu de la fenêtre et appelez SetLayeredWindowAttributes avec la valeur alpha souhaitée. Le code pourrait ressembler à ceci :

// Set WS_EX_LAYERED on this window 
SetWindowLong(hwnd, 
              GWL_EXSTYLE, 
              GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);

// Make this window 70% alpha
SetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA);

Notez que le troisième paramètre de SetLayeredWindowAttributes est une valeur qui varie de 0 à 255, 0 rendant la fenêtre complètement transparente et 255 la rendant complètement opaque. Ce paramètre imite la fonction BLENDFUNCTION plus polyvalente de la fonction AlphaBlend.

Pour rendre cette fenêtre complètement opaque à nouveau, retirez le bit WS_EX_LAYERED en appelant SetWindowLong puis demandez à la fenêtre de se repeindre. Retirer le bit est souhaité pour laisser le système savoir qu’il peut libérer de la mémoire associée à la superposition et à la redirection. Le code pourrait ressembler à ceci :

// Remove WS_EX_LAYERED from this window styles
SetWindowLong(hwnd, 
              GWL_EXSTYLE,
              GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);

// Ask the window and its children to repaint
RedrawWindow(hwnd, 
             NULL, 
             NULL, 
             RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);

Pour utiliser des fenêtres enfants superposées, l’application doit se déclarer compatible Windows 8 dans le manifeste.

Pour Windows 10/11, on peut inclure ce morceau de compatibilité dans son app.manifest pour le rendre conscient de Windows 10 :

...
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!-- Windows 10 GUID -->
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
    </application>
</compatibility>
...

Plus d’informations sur la modification du manifeste de l’application peuvent être lues ici : Manifestes d’application