3.5 Kontekst urządzenia
W piątej lekcji kursu GDI zajmiemy się bardzo ważnym elementem GDI jakim jest kontekst urządzenia. Programowo kontekst urządzenia to pewna struktura, która określa jak i gdzie mamy rysować. Wyobraźmy sobie biurko na, którym mamy położoną kartkę papieru, na której będziemy rysować, a obok kartki przybory, którymi będziemy rysować. Czymś takim jest kontekst urządzenia. Kartka na biurku, to obszar pulpitu lub okna po którym będziemy rysować, natomiast przybory koło kratki, to obiekty GDI w kontekście, które są używane do malowania na obszarze tego kontekstu.
Kontekst jest bardzo skomplikowanym obiektem, składa się z wielu atrybutów:
Obiekt pióra
Kontekst posiada własny obiekt pióra(poznałeś go w poprzedniej lekcji), którym rysuje linnie na swoim obszarze. Domyślnie(zaraz po utworzeniu) pióro jest koloru czarnego o stałej długości i grubości jednego piksela.
Pióro w kontekście możemy podmienić funkcją SelectObject(), natomiast pobrać uchwyt aktualnego pióra w kontekście funkcją GetCurrentObject(). Funkcje te omówione są w dalszej część lekcji.
Aktualna pozycja pióra(miejsce wskazujące)
Jest to pewien punkt na obszarze, na którym rysuje kontekst urządzenia, niektóre funkcje rysujące piórem zaczynają rysować właśnie od niego. Domyślnie po utworzeniu, punkt ten ma współrzędne (0,0). Funkcja, która zmienia jego położenie to MoveToEx(), natomiast punkt ten możemy pobrać funkcją GetCurrentPositionEx().
Pierwszy parametr to uchwyt do kontekstu, w którym mamy zmienić pozycję, drugi i trzeci to współrzędne nowego punktu, natomiast czwarty parametr to wskaźnik na strukturę w której zostaną umieszczone poprzednie współrzędne pozycji(te zastąpione). Jeżeli nie potrzebujemy znać poprzednich punktów, podajemy tu 0. Jeżeli funkcja się nie powiedzie, zwracane jest 0.
Pierwszy parametr to uchwyt do kontekstu urządzenia z którego pobieramy wspołrzędne pozycji pióra, natomiast drugi to wskaźnik na strukturę POINT, w której zostaną umieszczone pobierane współrzędne. Funkcja w razie niepowodzenia zwraca 0.
Tryb rysowania
Tryb rysowania określa nam w jaki sposób, stare piksele mają zostać przykryte przez naszą rysowaną figurę. Domyślnie zostają przykryte w pełni, natomiast GDI umożliwia odpowiednie mieszanie barw.
Obiekt pędzla
Pierwszym atrybutem pędzla jest sam obiekt pędzla, którego kontekst urządzenia będzie używał do wypełniania wnętrza figur. Domyślnie tworzony jest jednolity biały pędzel. Możemy go zmienić funkcją SelectObject(), natomiast pobrać funkcją GetCurrentObject().
Punkt odniesienia pędzla
Jest to punkt, którego używa się w przypadku pędzla z bitmapy, określa on skąd ma się zaczynać rysowanie bitmapy. Domyślnie jest to punkt (0,0). Ustawiamy go funkcją SetBrushOrgEx(), natomiast pobieramy GetBrushOrgSet()
Parametry i zwracna wartość są takie same jak w przypadku MoveToEx()
Parametry i zwracna wartość są takei same jak w przypadku GetCurrentPositionEx().
Obiekt bitmapy
Każdy kontekst ma swój obszar rysowania, jest nim właśnie obiekt bitmapy, to właśnie przestrzeń po, której rysuje. Domyślnie tworzona jest bitmapa monochromatyczna(czarno-biała) o wymiarach 1x1piksel. Zamienić obiekt możemy funkcją SetObject(), a pobrać GetCurrentObject(). Zwykle podczas tworzonego kontekstu, wybieramy od czego ma powstać obiekt bitmapy.
Tryb rozciągania
Tryb rozciągania przydaje się przy operacji skalowania bitmapy w danym kontekście urządzenia.
Atrybut ten określa pracę naszego kontekstu z operacjami tekstowymi.
Kolor tekstu
Ty chyba wszystko jasne. Określa jakiego koloru ma być wypisywany tekst w danym kontekście urządzenia. Domyślnie przyjmuje czarny kolor. Zmienić go możemy funkcją SetTextColor(), natomiast pobrać aktualny kolor funkcją GetTextColor().
Pierwszym parametr to uchwyt do modyfikowanego kontekstu, natomiast drugi to barwa koloru tekstu. Funkcja zwraca barwę koloru, który zmieniliśmy.
Parametrem jest uchwyt sprawdzanego kontekstu, natomiast funkcja zwraca aktualny kolor tekstu.
Tryb tła tekstu
Do wyboru mamy 2 tryby wypisywania tekstu, pierwszy z nich OPAQUE, wypisuje tekst z tłem w danym kolorze, natomiast drugi TRANSPARENT, wypisuje tekst bez tła, tło jest przezroczyste. Atrybut ten ustawia sie funkcją SetBkMode(), natomiast pobiera GetBkMode.
Pierwszy parmaetr do uchwyt do modyfikowanego kontekstu, drugi to nowy tryb tekstu(OPAQUE - tło, TRANSPARENT - przezroczystość). Funkcja zwraca poprzedni tryb tekstu.
Parametrem jest uchwyt do modyfikowanego kontekstu urządzenia, funkcja zwraca aktualny styl.
Kolor tła tekstu
W przypadku ustawienia trybu OPAQUE, jest to kolor tła tekstu. Funkcja, którą ustawia się dany kolor tła to SetBkColor(), natomiast pobrać kolor możemy funkcją GetBkColor().
Pierwszy parametr do uchwyt do modyfikowanego kontekstu, drugi to nowy kolor tła tekstu, funkcja zwraca poprzedni kolor.
Parametr do uchwyt do modyfikowanego kontekstu, funkcja zwraca aktualny kolor.
Obiekt czcionki
Jest to obiekt czcionki, którą aktualnie używa kontekst urządzenia do operacji tekstowych. Domyślną czcionką jest czcionka systemowa SYSTEM_FONT, obiekt ten możemy zmienić funkcją SelectObject(), natomiast pobrać GetCurrentObject().
Odstęp między znakami
Ten atrybut daje nam możliwość ustalenia odległości pomiędzy literami w danym kontekście. Domyślnie ustawiony jest na 0 pikseli. Możemy go ustawić funkcją SetTextCharacterExtra(), pobrać jak się zapewnie domyślacie GetTextCharacterExtra().
Pierwszy parametr to uchwyt do kontekstu, drugi to nowa odległość, funkcja zwraca starą wielkość, natomiast jeżeli się nie powiedzie, zwracane jest 0x80000000.
Parametr to wiadomo co i już nie będę się powtarzał, natomiast funkcja zwraca aktualny odstęp w pikeslach(o ile nie zmieniliśmy). Jeżeli funkcja się nie powiedzie zwracana jest wartość 0x8000000.
Wyrównanie tekstu
Atrybut ten odpowiada za umieszczenie tekstu według określonego układu. Dokładniej zajmiemy się nim przy wypisywaniu tekstu.
Region przycinania
Region przycinania pozwala ustawić część bitmapy, która będzie wyświetlana. Domyślnie wyświetlana jest cała bitmapa.Typ wypełniania wielokątów
Określa jak mają się łączyć regiony nakładające się na siebie.
Jako pierwszy parametr podajemy uchwyt do kontekstu urządzenia, w którym ma nastapić podmiana, drugim parametr to uchwyt do obiektu, który na zostać umieszczony w kontekście urządzenia. Uwaga, tutaj trzeba uważać na zwracaną wartość, otóż jest to uchwyt do poprzedniego kontekstu, tego który został podmieniony, gdyż będzie go trzeba zwolnić ręcznie funkcją DeleteObject(), która jako parametr przyjmuje uchwyt do zwalnianego obiektu. Obiekty, które są w danym kontekście urzadzenia są zwalniane w momencie zwalniania kontekstu, całą resztę trzeba zwolnić. Podczas podmiany obiekt, który wcześniej był w kontekście już nie będzie częścią kontekstu, więc jesteśmy odpowiedzialni za zwolnienie go, a nie kontekstu, mozna to robić tak:
brush=SelectObject(hdc,brush);
//natomiast temu, który wcześniej był w kontekście, nadajemy uchwyt tego co stworzyliśmy(zamiana obiektów)
DeleteObject(brush);
lub odrazu w jednym zapisie:
DeleteObject(SelectObject(hdc,brush));
Zwalniany jest wynik funkcji SelectObject(), czyli stary obiekt.
Inną funkcją, która służy do operacji na obiektach kontekstu, to GetCurrentObject, służy ona do uzyskiwania uchwytu do obiektów, które aktualnie znajdują się w kontekście urzadzenia.
GetCurrentObjectTworząc kontekst urządzenia, musimy wiedzieć od czego będzie ten kontekst urządzenia.
Jedną z możliwości jest pobranie kontekstu okna
GetDC pobiera kontekst okna, jako argument podajemy uchwyt do pobieranego okna, kiedy uzyskamy kontekst, będziemy mieli możliwość rysowania po roboczej części okna, poprzez kontekst urządzenia.
Możemy także pobrać, kontekst do całego okna, a nie tylko obszaru roboczego, czyli także paska tytułu, oraz reszty systemowych elementów okna, ale nie tylko tej częsci po której powinniśmy pracować. Robimy to funkcją GetWindowDC().
Kolejnym obszarem do którego możemy pobrać kontekst to cały pulpit, tak, możemy stworzyć program, który będzie mógł rysować po całym pulpicie. Robi się to Podając jako parametr 0 w funkcji GetDC.
Oczywiście każdy utworzony kontekst trzeba później zwolnić, robimy to funkcją ReleaseDC(), jako pierwszy parametr podajemy uchwyt do okna z jakiego powstał dany kontekst, drugi parametr to uchwyt do zwalnianego kontekstu.
Teraz trzeba sobie powiedzieć o bardzo ważnym procesie w windowsie, jakim jest odrysowywanie okienek windowsowych. Gdy mamy na pulpicie otwartych kilka okienek, a one w pewnych miejscach nakładają się na siebie, to aby ponownie pokazać okienko które było wcześniej zasłonięte, windows musi je odrysować, czasmi gdy komputer jest obciążony jakimś zadaniem lub program przestał odpowiadać, możemy zaobserwować, że fragment okna, który odsłoniliśmy jest biały nie odrysował się. Już wyjaśniam jak to się odbywa. Otóż, gdy nasze okienko(bądź fragment) było zasłonięte przez jakieś inne i nagle zostało odsłonięte do okienka wysyłany jest komunikat WM_PAINT, który właśnie mówi nam o konieczności odrysowania okna, to właśnie w obsłudze tego komunikatu powinniśmy umieścić polecenia rysujące nasz program, aby windows mógł odrysować fragment okienka. W tym celu musimy pobrać kontekst do fragmentu odrysowywanego okna. Robimy to funkcją BeginPaint(), a gdy już skończymy powinniśmy zwolnić go funkcją EndPaint().
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
INT WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR lStart,INT nShow)
{
WNDCLASSEX wc;
wc.hInstance=hInst;
wc.lpszClassName=
wc.lpfnWndProc=WndProc;
wc.style=CS_DBLCLKS;
wc.cbSize=sizeof(WNDCLASSEX);
wc.hIcon=LoadIcon(
wc.hIconSm=LoadIcon(
wc.hCursor=LoadCursor(
wc.lpszMenuName=
wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wc.cbWndExtra=
wc.cbClsExtra=
if(RegisterClassEx(&wc)==
HWND Okno=CreateWindowEx(
MSG msgs;
ShowWindow(Okno,nShow);
UpdateWindow(Okno);
while(GetMessage(&msgs,
{
TranslateMessage(&msgs);
DispatchMessage(&msgs);
}
return msgs.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wPar,LPARAM lPar)
{
HDC hdc;
PAINTSTRUCT ps;
switch(msg)
{
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
EndPaint(hwnd,&ps);
break;
case WM_DESTROY:
PostQuitMessage(
break;
default:
return DefWindowProc(hwnd,msg,wPar,lPar);
}
return
}
W tym miejscu trzeba sobie powiedzieć o funkcji UpdateWindow(), jej parametr to uchwyt do okna. Funkcja wysyła komunikat WM_PAINT do danego okna, powiadamiając, że trzeba odświeżyć całe okno. Innymi słowo funkcja rysuje całe okno jeszcze raz na nowo. Zwykle po pokazaniu okna funkcją ShowWindow(), uzywamy jej, gdyż zachodzi potrzeba odrysowania całego okna.
W następnej lekcji zajmiemy się już rysowaniem konkretnych figur na naszym oknie.