No więc w tej lekcji poznamy fucnkje pozwalające rysować nam na oknie poprzez kontekst urzadzenia. Najpierw pobierzmy sobie kontekst urządzenia na naszym oknie:

#include <windows.h>

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

INT WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR lStart,INT nShow)
{
  WNDCLASSEX wc;
  wc.hInstance=hInst;
  wc.lpszClassName=
"Klasa okna"
;
  wc.lpfnWndProc=WndProc;
  wc.style=CS_DBLCLKS;
  wc.cbSize=sizeof(WNDCLASSEX);
  wc.hIcon=LoadIcon(
0
,IDI_APPLICATION);
  wc.hIconSm=LoadIcon(
0
,IDI_APPLICATION);
  wc.hCursor=LoadCursor(
0
,IDC_ARROW);
  wc.lpszMenuName=
0
;
  wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
  wc.cbWndExtra=
0
;
  wc.cbClsExtra=
0
;
  if(RegisterClassEx(&wc)==
0
) return
0
;
  HWND Okno=CreateWindowEx(
0
,
"Klasa okna"
,
"Tytuł okna"
,WS_OVERLAPPEDWINDOW,
50
,
50
,
300
,
300
,
0
,
0
,hInst,
0
);
  MSG msgs;
  ShowWindow(Okno,nShow);
  UpdateWindow(Okno);
  while(GetMessage(&msgs,
0
,
0
,
0
))
  {
    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);
      
//funkcje rysujące

      EndPaint(hwnd,&ps);
      break;
    case WM_DESTROY:
      PostQuitMessage(
0
);
      break;
    default:
      return DefWindowProc(hwnd,msg,wPar,lPar);
  }
  return
0
;
}

struktura POINT

Zanim jednak jeszcze przejdziemy do omawiania poszczególnych figur, powiemy sobie pewnej strukturze POINT, którą w GDI gęsto sie używa.

struct POINT
{
  INT x;
  INT y;
}

Jak widać struktura POINT nie jest zbyt skomplikowana, zawiera 2 pola, x oraz y. Struktura wykorzystywana do zapisu współrzędnych punktu.

Piksele

Jest to właściwie najmniejsza figura geometryczna, piksel, czyli punkt, to najmniejsza część obrazu. Piksel charakteryzuje się kolorem.

COLORREF SetPixel(HDC hdc,INT x,INT y,COLORREF color);

Pierwszy parametr to uchwyt do kontekstu urządzenia, drugi i trzeci to współrzędnie w kontekście urzadzenia zmienianego piksela, czwarty parametr to właśnie kolor nowego piksela, natomiast funkcja zwraca kolor starego piskela.

Jeżeli nie potrzebujemy starego koloru piksela, mozemy użyć szybszej funkcji, do zmiany koloru piksela, jednak w msdn, mmy informację, że nie wszystkie urządzenia mogą obsługiwać tą funkcję, ale nie ma co się przejmować:

BOOL SetPixelV(HDC hdc,INT x,INT y,COLORREF color);

Funkcja ta przyjmuje takie same parametry jak SetPixel, natomiast nie zwraca starego piksela, lecz jeżeli się powiedzie zwraca 1, jezeli nie zwraca 0.

Możemy także pobrać kolor piksela:

COLORREF GetPixel(HDC hdc,INT x,INT y);

Drugi i trzeci parametr to współrzędne piksela w kontekście urzadzenia, natomiast funkcja zwraca nam kolor tego piksela.

Przykład:

...
COLORREF kolor;
...
hdc=BeginPaint(hwnd,&ps);
SetPixelV(hdc,
20
,
45
,RGB(
0
,
255
,
255
));
//piksel o współrzędnej (20,45) na kolor RGB(0,255,255)

SetPixel(hdc,
45
,
0
,RGB(
34
,
194
,
75
));
//piksel o współrzędnej (45,0) na kolor RGB(34,194,75)

kolor=GetPixel(hdc,
0
,
0
);
//piksel o współrzędnej (0,0)

EndPaint(hwnd,&ps);
...

Linia prosta

BOOL LineTo(HDC hdc,INT x,INT y);

Funkcja ta kreśli linię, z punktu położenia pióra(atrybut pióra), do punktu, który podamy w parametrach x i y. Linia ta będzie kreślona przez pióro w danym kontekście, więc będzie posiadała cechy tego pióra. Po zakończeniu położenie pióra(atrybut) będzie w miejscu zakończenia linni, czyli tych punktów, które podaliśmy w parametrach.

...
hdc=BeginPaint(hwnd,&ps);
MoveToEx(hdc,
50
,
50
,
0
);
//przeniesienie pozycji pióra na punkt (50,50)

LineTo(hdc,
100
,
100
);
//narysowanie linni do współrzędnej (100,100)
//w efekcie wywołań tych funkcji, narysujemy linię od punktu (50,50) do punktu (100,100)

EndPaint(hwnd,&ps);
...

Linia łamana

Linia łamana to poprostu kilka linni prostych połączonych końcami. Do rysowania łamanych używamy funkcji PolylineTo().

BOOL PolylineTo(HDC hdc,CONST LPPOINT lpPoint,DWORD lines);

W drugim parametrze podajemy wskaźnik na tablicę struktur typu POINT, każda kolejna struktura, to kolejny punkt łączenia krzywej, natomiast trzeci to ilość struktur w tablicy.

...
POINT point[
4
];
//tablica 4-ech punktów, krzywa będzie składała się z 4-ech prostych

point[
0
].x=
34
;
//współrzędna x 1 punktu

point[
0
].y=
78
;
//współrzędna y 1 punktu

point[
1
].x=
156
;
//współrzędna x 2 punktu

point[
1
].y=
23
;
//współrzędna y 2 punktu

point[
2
].x=
78
;
//współrzędna x 3 punktu

point[
2
].y=
256
;
//współrzędna y 3 punktu

point[
3
].x=
395
;
//współrzędna x 4 punktu

point[
3
].y=
301
;
//współrzędna y 4 punktu

...
hdc=BeginPaint(hwnd,&ps);
MoveToEx(hdc,
20
,
20
,
0
);
//Punkt początku rysowania

PolylineTo(hdc,point,
4
);
EndPaint(hwnd,&ps);
...

Łuk

Łuk jest częścią obwodu elipsy, funkcja, która rysuje łuki:

BOOL ArcTo(HDC hdc,INT nLeftRect,INT nTopRect,INT nRightRect,INT nBottomRect,INT nXStart,INT nYStart,
INT nXEnd,INT nYEnd);

A to objaśnienie parametrów:

Funkcja najpierw rysuje linię z pozycji pióra, następnie rysuje łuk i zostawia pozycje pióra w ostatnim punkcie rysowania.

Prostokąt

Do narysowania figury zamkniętej, będziemy używać nie tylko pióra, ale także pędzela. Pióro służy do rysowania odwodu figury, natomiast pędzel jego wnętrza.

BOOL Rectangle(HDC, INT nLeftRect,INT nTopRect,INT nRightRect,INT nBottomRect);

Funkcja ta służy do rysowania prostokąta, przy użyciu aktualnego pióra i pędzla w kontekście, objaśnienie parametrów:

Do rysowania prostokąta możemy użyć innej funkcji:

BOOL FillRect(HDC hdc,CONST LPRECT lprc,HBRUSH hbr);

Jako drugi parametr podajemy wskaźnik na strukturę RECT, natomiast trzeci parametr to uchwyt do pędzla. Funkcja ta różni się tym, że nie używa obiektów pędzla i pióra, które są w kontekście. Pióra wogóle nie używa, gdyż funkcja ta rysuje prostokąt bez obramowania, a pędzel jakim zostanie wypełniona figura podajemy jako parametr. W strukturze RECT umieszczamy współrzędne dwóch punktów, jej elementy są odpowiednikami, parametrów z poprzedniej funkcji.

struct RECT
{
  INT left;
  INT top;
  INT right;
  INT bottom;
}

Istnieje także funkcja do rysowania samego obramowania prostokata FrameRect(), ale rysowanie obramowania odbywa się dość nietypowo, bo pędzlem(z parametru), grubość rysowanego obramowania będzie wynosić 1 piksel.

INT FrameRect(HDC hdc,CONST LPRECT lprc,HBRUSH hbr);

Jest jeszcze jedna funkcja operująca na prostokącie, jednak nie można powiedzieć, aby cokolwiek malowała. InvertRect() służy do odwracania kolorów w prostokątnym obszarze(podajemy w parametrze). Polega to na tym, że każdy piksel w danym obszarze prostokątnym odwraca swoją wartość, poprzez operację odwrócenia bitowego.

BOOL InvertRect(HDC hdc,CONST LPRECT lprc);

Dowolny wielokąt

Do rysownaia dowolnego wielokąta służy funkcja Polygon():

BOOL Polygon(HDC hdc,CONST LPPOINT lppoint,INT nCount);

Funkcja ta jest podobna do funkcji Polyline(rysowanie łamanej), jako drugi parametr przyjmuje wskaźnik na tablicę punktów, z kolejnymi wierzchołkami, pióro z kontekstu łączy kolejne wierzchołki, także pierwszy z ostatnim zamykając figurę i wypełniając ją pędzlem.

...
POINT points[]={{
10
,1
0
},{
30
,
10
},{
20
,
20
}};
...
hdc=BeginPaint(hwnd,&ps);
Polygon(hdc,points,
3
);
//trójkąt

EndPaint(hwnd,&ps);
...

Elipsa

Funkcją rysującą elipsę jest Ellipse().

BOOL Ellipse(HDC hdc,INT nLeftRect,INT nTopRect,INT nRightRect,INT nBottomRect);

Jest ona bardzo podobna do funkcji Rectangle(), wszystkie parametry są identyczne, ba nawet określają tą samą figurę: prostokąt. Spytasz się jak to prostokat, skoro rysujemy elipsę? Ponieważ elipsę rysuje się na podstawie prostokąta, a ona jest wpisana właśnie w ten prostokąt, rysunek powinien wszystko wyjaśnić:

Wycinek elipsy

W przypadku wycinka elipsy zasada jak taka sama, jak przy rysowaniu łuku z tym, że malujemy także wnętrze z promieniami. Funkcja rysująca wycinek jest niemal identyczna do funkcja rysująca łuk:

BOOL Pie(HDC hdc,INT nLeftRect,INT nTopRect,INT nRightRect,INT nBottomRect,INT nXStart,INT nYStart,
INT nXEnd,INT nYEnd);

Odcinek elipsy

Ostatnią funkcją pracującą z elipsami jest Chord(), rysuje ona wycinek elipsy, spójrzmy na funkcję i obrazek przedstawiający jaką część figury rysuje:

BOOL Chord(HDC hdc,INT nLeftRect,INT nTopRect,INT nRightRect,INT nBottomRect,INT nXStart,INT nYStart,
INT nXEnd,INT nYEnd);

Prostokąt z zaokrąglonymi rogami

Ostatnią figurą jaką poznamy będzie dość dziwaczny prostokąt, który ma zaokrąglone rogi. Funkcja:

BOOL RoundRect(HDC hdc,INT nLeftRect,INT nTopRect,INT nRightRect,INT nBottomRect,INT nWidth,INT nHeight);

To już wszystkie poznane funkcje rysujące figury w GDI, w następnej lekcji nasze rysunki na oknie przystroimy bitmapami.