Windows gebruiken

In de voorbeelden in deze sectie wordt beschreven hoe u de volgende taken uitvoert:

Een hoofdvenster maken

Het eerste venster dat een toepassing maakt, is meestal het hoofdvenster. U maakt het hoofdvenster met behulp van de functie CreateWindowEx, waarbij u de vensterklasse, vensternaam, vensterstijlen, grootte, positie, menugreep, exemplaargreep en aanmaakgegevens opgeeft. Een hoofdvenster behoort tot een toepassingsgedefinieerde vensterklasse, dus u moet de vensterklasse registreren en een vensterprocedure voor de klasse opgeven voordat u het hoofdvenster maakt.

De meeste toepassingen gebruiken doorgaans de stijl WS_OVERLAPPEDWINDOW om het hoofdvenster te maken. Deze stijl geeft het venster een titelbalk, een venstermenu, een formaatrand en knoppen minimaliseren en maximaliseren. De functie CreateWindowEx retourneert een ingang die het venster uniek identificeert.

In het volgende voorbeeld wordt een hoofdvenster gemaakt dat hoort bij een toepassingsgedefinieerde vensterklasse. De naam van het venster, hoofdvenster, wordt weergegeven in de titelbalk van het venster. Door de stijlen WS_VSCROLL en WS_HSCROLL te combineren met de stijl WS_OVERLAPPEDWINDOW, maakt de toepassing een hoofdvenster met horizontale en verticale schuifbalken naast de onderdelen van de WS_OVERLAPPEDWINDOW stijl. De vier exemplaren van de CW_USEDEFAULT constante stellen de oorspronkelijke grootte en positie van het venster in op de door het systeem gedefinieerde standaardwaarden. Door NULL- op te geven in plaats van een menugreep, wordt in het venster het menu gedefinieerd voor de vensterklasse.

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); 

U ziet dat in het voorgaande voorbeeld de functie ShowWindow wordt aangeroepen nadat het hoofdvenster is gemaakt. Dit gebeurt omdat het systeem niet automatisch het hoofdvenster weergeeft nadat het is gemaakt. Door de vlag SW_SHOWDEFAULT door te geven aan ShowWindow, staat de toepassing toe dat het programma waarmee de toepassing is gestart, de initiƫle weergavestatus van het hoofdvenster kan instellen. De functie UpdateWindow verzendt het venster het eerste WM_PAINT bericht.

Kindvensters maken, opsommen en dimensioneren

U kunt het clientgebied van een venster onderverdelen in verschillende functionele gebieden met behulp van onderliggende vensters. Het maken van een onderliggend venster lijkt op het maken van een hoofdvenster. U gebruikt de functie CreateWindowEx. Als u een venster van een toepassingsgedefinieerde vensterklasse wilt maken, moet u de vensterklasse registreren en een vensterprocedure opgeven voordat u het onderliggende venster maakt. U moet het kindvenster de stijl WS_CHILD geven en een oudervenster voor het kindvenster opgeven wanneer u het maakt.

In het volgende voorbeeld wordt het clientgebied van het hoofdvenster van een toepassing verdeeld in drie functionele gebieden door drie onderliggende vensters van gelijke grootte te maken. Elk onderliggend venster heeft dezelfde hoogte als het clientgebied van het hoofdvenster, maar elk venster heeft een derde breedte. In het hoofdvenster worden de kindvensters gemaakt als reactie op het WM_CREATE bericht dat het hoofdvenster ontvangt tijdens het aanmaken van zijn eigen venster. Omdat elk onderliggend venster de stijl WS_BORDER heeft, heeft elk een dunne lijnrand. Ook omdat de stijl WS_VISIBLE niet is opgegeven, wordt elk onderliggend venster in eerste instantie verborgen. Merk ook op dat aan elk onderliggend venster een onderliggend-venster-ID is toegewezen.

Het hoofdvenster bepaalt de grootte en positie van de onderliggende vensters als reactie op het WM_SIZE bericht, dat het hoofdvenster ontvangt wanneer de grootte ervan verandert. Als reactie op WM_SIZEhaalt het hoofdvenster de dimensies van het clientgebied op met behulp van de functie GetClientRect en worden vervolgens de dimensies doorgegeven aan de EnumChildWindows-functie. EnumChildWindows geeft de handle door aan elk onderliggend venster, op volgorde, aan de door de toepassing gedefinieerde EnumChildProc callback-functie. Deze functie bepaalt de grootte en positie van elk kindvenster door de functie MoveWindow aan te roepen; de grootte en positie zijn gebaseerd op de afmetingen van het clientgebied van het hoofdvenster en de identifier van het kindvenster. Daarna roept EnumChildProc- de functie ShowWindow- aan om het venster zichtbaar te maken.

#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;
}

Een venster vernietigen

U kunt de DestroyWindow functie gebruiken om een venster te vernietigen. Normaal gesproken verzendt een toepassing het WM_CLOSE bericht voordat een venster wordt vernietigd, waardoor het venster de mogelijkheid krijgt om de gebruiker om bevestiging te vragen voordat het venster wordt vernietigd. Een venster met een venstermenu ontvangt automatisch het WM_CLOSE bericht wanneer de gebruiker klikt op sluiten in het venstermenu. Als de gebruiker bevestigt dat het venster moet worden vernietigd, roept de toepassing DestroyWindow-aan. Het systeem verzendt het WM_DESTROY bericht naar het venster nadat het van het scherm is verwijderd. Als reactie op WM_DESTROYslaat het venster de gegevens op en worden alle toegewezen resources vrijgemaakt. Een hoofdvenster sluit de verwerking van WM_DESTROY door de functie PostQuitMessage aan te roepen om de toepassing af te sluiten.

In het volgende voorbeeld ziet u hoe u om bevestiging van de gebruiker wordt gevraagd voordat u een venster vernietigt. Als reactie op WM_CLOSEwordt een dialoogvenster weergegeven met Ja-, Nee-en knoppen annuleren. Als de gebruiker op Jaklikt, wordt DestroyWindow- aangeroepen; anders wordt het raam niet vernietigd. Omdat de toepassing het WM_CLOSE bericht verwerkt, wordt 0 in alle gevallen geretourneerd. Omdat het venster dat wordt vernietigd een hoofdvenster is, roept het voorbeeld PostQuitMessage- aan als reactie op 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;

Gelaagde Vensters gebruiken

Als u een dialoogvenster wilt weergeven als een doorzichtig venster, maakt u eerst het dialoogvenster zoals gebruikelijk. Stel vervolgens op WM_INITDIALOGde gelaagde bit van de uitgebreide stijl van het venster in en roep SetLayeredWindowAttributes met de gewenste alfawaarde aan. De code kan er als volgt uitzien:

// 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);

Houd er rekening mee dat de derde parameter van SetLayeredWindowAttributes een waarde is die varieert van 0 tot 255, waarbij 0 het venster volledig transparant maakt en 255 het volledig ondoorzichtig maakt. Met deze parameter wordt de veelzijdigere BLENDFUNCTION van de AlphaBlend functie nagebootst.

Als u dit venster volledig ondoorzichtig wilt maken, verwijdert u de WS_EX_LAYERED bit door SetWindowLong aan te roepen en vervolgens het venster opnieuw te laten repainten. Het verwijderen van de bit is gewenst om het systeem te laten weten dat het geheugen kan vrijmaken dat is gekoppeld aan gelaagdheid en omleiding. De code kan er als volgt uitzien:

// 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);

Om gebruik te maken van gelaagde onderliggende vensters, moet de toepassing in het manifest aangeven dat het compatibel is met Windows 8.

Voor Windows 10/11 kunt u dit compatibiliteitsfragment opnemen in de app.manifest om het windows 10-bewust te maken:

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

Meer informatie over het wijzigen van app-manifesten vindt u hier: toepassingsmanifesten