19.1.2002
V tomto pokračování se seznámíme s dalším objektem GDI - bitmapou. Ukážeme si jak vykreslit bitmapu uloženou v prostředcích programu do okna. V té souvislosti si ukážeme použití štětců tvořených vzorkem z bitmapy.
Na obrázku vidíte konečný výsledek dnešního výkladu: jde o okno, jehož štětec pozadí je definován vzorkem z bitmapy a v handleru zprávy WM_PAINT je uprostřed okna vykreslena bitmapa (fotografie v true-color barevné hloubce).
Z pohledu programátora je bitmapa grafický objekt podobný jako nám již známá pera nebo štětce. Znamená to že musíme "nějakým způsobem" získat handle bitmapy (ať už již existující nebo námi vytvořené), poté tento handle vybrat do kontextu zařízení, s kterým pak můžeme "pracovat". Jednotlivé pixely tohoto kontextu zařízení (obsahujícího bitmapu) pak představují barevné body tvořící bitmapu. Barva každého pixelu je určena třemi barevnými složkami - červená, zelená a modrá - každá z nich může mít definovanou intenzitu v rozsahu 0-255 (1 BYTE).
Nejjednodušším způsobem získání handle bitmapy je její načtení z prostředků (resources) programu funkcí LoadBitmap:
HBITMAP LoadBitmap( HINSTANCE hInstance, // handle modulu LPCTSTR lpBitmapName // jméno zdroje - bitmap );
Tato funkce nám vrátí handle bitmapy. Často chceme získat nějaké informace o takto načtené bitmapě. Obvykle nás zajímají především její rozměry (z důvodu jejího umístění při kreslení). Protože bitmapa je grafický objekt, použijeme již známou funkci GetObject:
int GetObject( HGDIOBJ hgdiobj, // handle grafického objektu int cbBuffer, // velikost bufferu LPVOID lpvObject // buffer pro informace o objektu );
V případě bitmapy je bufferem pro informaci o objektu struktura BITMAP:
typedef struct tagBITMAP { LONG bmType; LONG bmWidth; LONG bmHeight; LONG bmWidthBytes; WORD bmPlanes; WORD bmBitsPixel; LPVOID bmBits; } BITMAP, *PBITMAP;
Většinou chceme bitmapu vykreslit do kontextu zařízení okna. Musíme proto nejprve vytvořit vlastní paměťový kontext zařízení, do něj vybrat handle bitmapy a poté můžeme použít tu nejjednodušší funkci pro kopírování (případně další bitové operace) kontextů zařízení - BitBlt:
BOOL BitBlt( HDC hdcDest, // handle cílového DC int nXDest, // x-souřadnice horního levého rohu int nYDest, // y-souřadnice horního levého rohu int nWidth, // šířka cílového obdélníka int nHeight, // výška cílového obdélníka HDC hdcSrc, // handle zdrojového DC int nXSrc, // x-souřadnice levého horního rohu int nYSrc, // y-souřadnice DWORD dwRop // typ rastrové operace );
V tom nejjednodušším případě kopírování bitmapy do kontextu zařízení okna je cílovým hdcDest kontext okna a hdcSrc kontext bitmapy. 2 - 5 parametr definují obdélník v cílovém kontextu zařízení, do kteréhoje bitmapa kreslena a parametry nXSrc a nYSrc definují levý horní roh v bitmapě, od kterrého se začíná kreslit. Pokud je různý od souřadnice (0,0) jde o výřez z bitmapy.
Pokud tedy chceme vykreslit celou bitmapu, musíme nejprve zjistit její rozměry (funkcí GetObject), které pak uvedeme jako parametry nXDest a nYDest. Pro běžné kopírování je pak typ rastrové operace definován hodnotou SRCCOPY. O dalších možnostech si řekneme někdy příště, nyní si ukažme výpis kódu, který (v handleru zprávy WM_PAINT) realizuje to co vidíme na úvodním screen-shotu. Nejprve k pozadí okna. Již víme že každá třída okna má definovaný štětec, tvořící výplň jeho pozadí. Kromě již probíraných typů štětců existuje ještě štětec tvořený vzorkem bitmapy, který získáme funkcí CreatePatterBrush:
HBRUSH CreatePatternBrush( HBITMAP hbmp // handle bitmapy );
Jediné co potřebujeme, je opět handle bitmapy. V projektu jsou přidané do zdrojů 2 bitmapy (IDB_BACKGROUD a IDB_BITMAP1). Pozadí tedy definujeme při registraci třídy okna takto:
// .... kód registrace třídy okna wcex.hbrBackground = CreatePatternBrush(LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BACKGROUND)))
Nyní již zbývá jen handler zprávy WM_PAINT:
void OnPaint(HDC hdc) { BITMAP bitmap; RECT rect; GetClientRect(hwndMain, &rect); HDC hdcBitmap = CreateCompatibleDC(hdc); HBITMAP hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1)); GetObject(hBitmap, sizeof(bitmap), &bitmap); SelectObject(hdcBitmap, hBitmap); int xPos = (rect.right - bitmap.bmWidth) / 2; int yPos = (rect.bottom - bitmap.bmHeight) / 2; BitBlt(hdc, xPos, yPos, bitmap.bmWidth, bitmap.bmHeight, hdcBitmap, 0,0, SRCCOPY); DeleteObject(hBitmap); DeleteDC(hdcBitmap); }
Jak je vidět, po použití musíme opět bitmapu zrušit funkcí DeleteObject, stejně jako jiný grafický object. Pro vytvoření kontextu zařízení bitmapy jsem použit tu nejjednodušší funkci CreateComaptibleDC:
HDC CreateCompatibleDC( HDC hdc // handle to DC );
která nám vytvoří kontext zařízení se stejnými vlastnostmi jako zadaný existující kontext zařízení, v našem případě kontext okna.
Doprovodný projekt je ke stažení zde: win_api_19.zip
Školení
Kontakt
739 219 991
live:radekchalupa_1
Nové články