Példa: simple_window

Az ablak kirakása nem túl nehéz, csak előbb sok mindent meg kell csinálni. Szóval nem nehéz, csak macerás. Ha jól látom, akkor a win32-re ez végig igaz lesz! Gépelünk, gépelünk..

Jöjjön előbb egy példa, amin keresztül boncolhatjuk azt a bizonyos orvosi lovat!

#include <windows.h>

const char g_szClassName[] = "myWindowClass";

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    //Step 1: Registering the Window Class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "The title of my window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

Akár kis is próbálhatjuk hogy mit alkottunk! Töltsük be a példaprogramok közül, és futtassuk le!

Megjelent egy hagyományos ablak, amiben ugyan nincs semmi, de átméretezhető, és a sarkában ott vannak a vezérlő gombok. És még fejléce is van neki! Nahát! És mindez alig nyolcvan sorba került! ;o)
Nézzük meg, hogy mi a retek ez a sok programsor!

Első lépés:

 

Elöljáróban annyit, hogy a Window osztálynak semmi köze nincs a C++ osztályokhoz! Ez tárolja az ablakhoz felhasznált ikont, a vezérlőket, és a háttérszínt. Ezeket a tulajdonságokat nem kell minden ablakhoz külön külön beállítani, elég csak az ablakokat létrehozni. Persze ablakonként is állíthatók ha kell.

 const char g_szClassName[] = "myWindowClass";


Ez a változó tárolja az ablak osztályának a nevét, ezzel fogja a rendszer regisztrálni az ablakunkat.
A következőkben létrehozunk egy WNDCLASSEX típusú változót (aminek van pár beállítható értéke), majd a RegisterClassEx() függvénnyel regisztráljuk.

 

WNDCLASSEX wc;

wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = g_szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; }


Akkor tételesen az egyes mezők jelentéséről:
cbSize: Jelzi a struktúra méretét
style:Egyszerűen legyen 0
lpfnWndProc:Mutató a window eljárásra
cbClsExtra: Lefoglalt memória mennyisége az extra adatok számára. Legyen 0!
cbWndExtra: Ugyanaz, csak ablakonként. Szintén 0.
hInstance: Az alkalmazás példány kezelője (ez a WinMain() első paramétere).
hIcon: Nagy (32x32) ikon, amit az Alt+Tab nyomásakor látunk
hCursor: Az ablak felett látható kurzor
hbrBackground: Háttér ecset, ami megadja az ablak színét
lpszMenuName: A menü erőforrás neve
lpszClassName: Azonosító név
hIconSm: Kicsi (16x16) ikon, amit a taskbar-on és az ablak bal felső sarkában látunk

Ezután meghívjuk a RegisterClassEx() eljárást, ami sikertelenség esetén dob egy üzenetet.

Második lépés:

 

Ha már regisztráltunk, akkor létrehozhatjuk az ablak példányunkat.

HWND hwnd;
hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "The title of my window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
        NULL, NULL, hInstance, NULL);

Az első paraméter egy szebb dizájnt ad az ablak keretének (3D). Ha látni szeretnéd a különbséget, akkor állítsd próbából 0-ra az értékét!

Következőként az osztály nevét adjuk meg.

A WS_OVERLAPPEDWINDOW egy ablak stílus paraméter. Sok ilyen van, ki kell próbálni, hogy melyik mit csinál.

A CW_USEDEFAULT, CW_USEDEFAULT, 240, 120 az ablak elhelyezését határozza meg. X,Y,Szélesség,Magasság formátumban. Az értékek pixelben értendőek, a képernyő bal felső sarka a 0,0. Amikor CW_USEDEFAULT érték szerepel, akkor a rendszer automatikusan helyezi el az ablakot a képernyőn.

Most jön a ParentWindowHandle, a MenuHandle, ApplicationInstanceHandle, WindowCreationData négyes.
ParentWindowHandle: Ha egy gombot teszünk az ablakra, akkor a gombot gyermeknek, az ablakot pedig szülőnek nevezzük. Mivel ez az ablak egy legfelső objektum, nincs szülője, ezért ez NULL.
MenuHandle: A menü is NULL, mert nincs olyanunk.
ApplicationInstanceHandler: A WinMain() első paraméterét átadjuk
WindowCreationData:
Nem használjuk, NULL

 Ténykedésünk eredményét mindig ellenőrízzük le, ezt végzi el az alábbi pár sor:

 if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

Ha minden jó volt, akkor a WinMain() utolsó paraméterének segítségével megjeleníthetjük az ablakunkat

ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

 

Az nCmdShow paraméter opcionális, egyszerűen írhatnánk azt is, hogy SW_SHOWNORMAL. Mégis, ezzel be lehet állítani pár dolgot az ablakon. Ez nem túl tiszta még, majd kiderül.

Azt hiszed végeztünk? Hát nem!

Harmadik lépés:

 while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;

 Ez a program motorja!

A GetMessage() üzenetet kap az alkalmazások üzenet sorából. Minden alkalommal amikor a felhasználó mozgatja az egeret, gépel a billentyűzeten, kattint a menün, stb, a rendszer generál egy üzenetet a program üzenetsorába. A GetMessage() hívásával kiolvassuk a következő rendelkezésre álló üzenetet, és töröljük a sorból.
A TranslateMessage() további dolgokat tesz a billentyűeseményekkel.
A DispatchMessage() tovább küldi az üzenetet, hátha nem nekünk szólt. A rendszer tudni fogja kinek kell továbbítania.

Negyedik lépés:

 

Eldöntjük, hogy a kapott üzenetekkel mit kezdjünk.

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

A HWND paraméter címzi az aktuális ablakot. Például a bezárás gombot megnyomva innen tudjuk, hogy melyik ablakot is kell bezárni. A WM_CLOSE üzenet a rendszer általános parancsa, ha Alt+F4-et nyomunk, vagy az ablak sarkában az 'x'-et. A rendszer automatikusan bezárná az ablakot, de célszerű ezt inkább manuálisan megtenni, mert így a kilépés előtt még megtehetünk dolgokat. Például mentés kilépés előtt, kilépési megerősítés kérése, stb.
Ha meghívjuk a DestroyWindow() eljárást, akkor a rendszer küld egy WM_DESTROY üzenetet, amit még utoljára elcsíphetünk. Ekkor a PostQuitMessage() segítségével küldhetünk egy végeredmény kódot az esetleges hívó program számára.

Egyenlőre ennyi, most örülünk :)

A bejegyzés trackback címe:

https://win32learning.blog.hu/api/trackback/id/tr506249733

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása