'winapi'에 해당되는 글 33건

  1. 2010.07.21 WinApi 그래픽 [색상][펜][브러쉬]
  2. 2010.07.21 WinApi 그래픽 [GetStockObject]
posted by nsakura 2010. 7. 21. 16:40

예전 dos시절의 프로그램을 생각해보자

색상을 WHITE YELLOW RED등 매크로 상수로 색상을 표현했었다.

해봤자 16개 색상밖에 사용을 못하니.

하지만 윈도우에서는 다르다.

윈도우는 최대 천육백만가지의 색상값을 정의할수있으니 말이다.

그래서 윈도우즈에서 색상값을 표현하기 위해서는 COLORREF라는 데이터형을 사용하는데 다음과같이 정의 되어있다

typedef DWORD COLORREF;

보다싶이 COLORREF 형은 부호없는 32비트 크기의 정수형이며 8비트씩 R G B의 농도를 나타내며 상위 8비트는 사용하지

않는다.

하지만 상당히 불편하기 때문에. RGB 매크로 함수를 사용하며 이 매크로는 다음과 같이 정의

되어있다.

#define RGB(r,g,b)((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|((((DWORD)(BYTE)(b))<<16)))

각각의 인수는 R G B의 농도 이고 이 값을 조립하여 하나의 32 비트의 색상값을 만들어 낸다.

그외에 제공하는 색상관련 메크로 함수가 3개가 있다.

#define GetRValue(rgb) ((BYTE)(rgb))
#define GetBValue(rgb) ((BYTE)(((WORD)(rgb))>>8))
#define GetGValue(rgb) ((BYTE)((rgb)>>16))


이 메크로 함수들은 각 색상을 분리하는데 사용한다.

색상에 대해서는 그만 설명하고

펜을 실습을 해보자.

펜을 만드는 함수는  다음과 같다.

HPEN CretePen(int fnPenStyle, int nWidth, COLORREF crColor);


fnPenStyle

PS_SOLID  일반 선 

PS_DASH ----

PS_DOT ........

PS_DASHDOT _._._.

PS_DASHDOTDOT_.._.._

등이 있다,

nWidth

선의 폭을 설정한다.

crColor

선의 색을 설정한다.

그럼 예제를 통해 사용해보자.

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam){
 HDC hdc;
 PAINTSTRUCT ps;
 HPEN testpen,savepen;
 switch(iMessage){
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  testpen=CreatePen(PS_DASHDOTDOT,1,RGB(125,88,255));
  savepen=(HPEN)SelectObject(hdc,testpen);

  Rectangle(hdc,100,100,400,400);
  SelectObject(hdc,savepen);
  DeleteObject(testpen);
  EndPaint(hWnd,&ps);
 }

 return (DefWindowProc(hWnd,iMessage,wParam,lParam));

}

GDI 오브젝트는 스톡오브젝트와 달리

사용했으면 반납을 해야한다.

즉 메모리를 사용했으면 다사용하고 반납을 해야한다는 것이다.

그 반납하는 함수가 바로

DeleteObject(testpen);

가 되겠습니다.

BOOL DeleteObject(HGDIOBJ hObject);

즉 반납하고자하는 GDI오브젝트의 핸들만 인수로 넘겨주면 된다.

주의할점은 현재 선택되어있는 GDI Object는 반납할수 없다.

그래서 사용한게 savepen을 이용한 것이다. 삭제하긱전에 savepen으로 교체하고

반납하면 된다.

그래서

  SelectObject(hdc,savepen);
  DeleteObject(testpen);

 좀더 고급스럽게 바꾸면

DeleteObject(SelectObject(savepen));

무엇을 사용할건지는 편한것을 사용하도록.

참고로 위의 코드의 결과는 다음과 같다.


위의 코드는 썰렁한 부분이 있는데 바로... 안쪽. 안쪽의 빈공간을 채우고 싶다는.. 욕구가 안생기는가...

브러쉬를 이용하면 색을 칠할수있는데

브러쉬를 만드는 함수는 두가지가있다.

HBRUSH CreateSolidBrush(COLORREF crColor);

이 함수는 단색 브러쉬만 만들수있고 색상만 인수로 전달한다.

다음 함수는

HBRUSH CreateHatchBrush(int fnStyle, COLORREF clrref);

인데 특징으로서는 색상뿐만 아니라. 무늬도 같이 지정할수있다. 지정할수 있는 무늬의 종류는 다음과 같다.

 HS_BDIAGONAL  좌하향 줄무늬
 HS_CROSS  바둑판 모양
 HS_DIAGCROSS  좌하향 및 우하향 줄무늬
 HS_FDIAGONAL 우하향 줄무늬
 HS_HORIZONTAL  수평선
 HS_VERTICAL  수직선


그럼 예제를 통해서 사용해보자 PEN에서 사용한 소스를 조금 수정해보자.

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam){
 HDC hdc;
 PAINTSTRUCT ps;
 HPEN testpen,savepen;
 HBRUSH testbrush,savebrush;

 switch(iMessage){
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  
  testpen=CreatePen(PS_DASHDOTDOT,1,RGB(125,88,255));
  testbrush=CreateHatchBrush(HS_DIAGCROSS,RGB(225,128,150));
  
  savepen=(HPEN)SelectObject(hdc,testpen);
  savebrush=(HBRUSH)SelectObject(hdc,testbrush);
  
  Rectangle(hdc,100,100,400,400);
  
  DeleteObject(SelectObject(hdc,savepen));
  DeleteObject(SelectObject(hdc,savebrush));

  EndPaint(hWnd,&ps);
 }

 return (DefWindowProc(hWnd,iMessage,wParam,lParam));

}

코드의 결과는 다음과 같다.

[그림판으로 스샷을 찍으니.. 색상이 많이 죽네요.]
posted by nsakura 2010. 7. 21. 15:08

어제부로 리소스는 끝났습니다.

참으로 간단하고 그렇게 어렵지도 않았지요.

오늘부터는 그래픽에 대해 알아보도록 합니다.

포스트에 앞서 일일히 코드를 다 붙여넣는건 상당히 귀찮다. 그리고 이때까지 복사하기를 한건.

눈에 익으라고 그렇게 복사하기 한것이다.

이제 이쯤 되었으니 메인함수는 거의 변함이 없다는걸 알수있고 몇몇 사람들은 이미 복사해서 사용하고있을수도 있다.

즉 내가 말하는건 왠만해서 WinMain은 변화된부분만

그리고 WndProc만 적기로 했다. [사실 나도 귀찮다.]

이점 유의하시고 보기 바란다.

우리가 앞에 출력부분에서 DC를 조금 배웠을 것이다.

그럼 GDI에 대해 좀더 알아보도록하자

GDI (Graphic Device Interface)

GDI는 화면, 프린터 등의 모든 출력 장치를 제어하는 윈도우즈의 핵심 모듈 이다.

GDI Object란 그래픽 출력에 사용되는 도구를 말하는데

이에는 [펜 브러시 비트맵 폰트 등등 이 모두 GDI 오브젝트 이다.]

현실세계의 필통과 이라고 생각하면 편할지도 모르겠다.

GDI Object는 모두 핸들로 관리되므로 우리는 다만 GDI 오브젝트를 생성하는 함수를 부르고 이 함수가 리턴하는 핸들을 받아서

사용하기만 하기만 하면된다.

[ps 마소는 api의 내부는 공개하지 않습니다. 우리는 사용만할뿐]

GetDC나 BeginPaint 함수에  의해 처음 만들어졌을 때 디폴트로 선택한 GDI 오브젝트는 다음과 같다.

 펜  HPEN   선을 그릴 때 사용한다  검정색의 가는 실선 
 브러쉬  HBRUSH  면을 채울 때 사용한다  흰색
 폰트  HFONT  문자 출력에 사용되는 글꼴  시스템 글쫄 
 비트맵  HBITMAP  비트맵 이미지  선택되지 않음
 팔레트  HPANLETTE  팔레트  선택되지 않음
 리전  HRGN  화면상의 영역  선택되지 않음


StockObject

스톡 오브젝트는 윈도우가 기본적으로 제공하는 GDI 오브젝트를 말하는데

자주 사용되서 OS가 부팅할 때부터 미리 만들어 놓는다. 우리가 부탁한것도 아니기 때문에 다사용하고나서도 굳이 반납할필요는 없다.

알아서 반납이 된다.

다음 함수로 핸들을 얻어 사용하면 되다

HGDIOBJ GetStockObject(int fnObject)

뭐 인수에는 사용하고자하는 스톡 오브젝트를 지정하는데 ...

스톡 오브젝트는 다음과 같다.

 BLACK_BRUSH  검정 브러시
 GRAY_BRUSH  회색 브러시
 NULL_BRUSH  투명 브러시
 WHITE_BRUSH  흰색 브러시
 DKGRAY_BRUSH  짙은 회색 브러시
 LTGRAY_BRUSH  옅은 회색 브러시
 DC_BRUSH  색상 브러시. SetDCBrushColor 함수로 설정한다.
 BLACK_PEN  검정색 펜
 WHITE_PEN  흰색 펜
 NULL_PEN  투명 펜
 DC_PEN  색상 펜. SetDCPenColor 함수로 설정한다.
 ANSI_FIXED_FONT  고정폭 폰트
 ANSI_VAR_FONT  가변폭 폰트
 DEFAULT_PALETTE  시스템 팔레트


자 실습의 시간이 돌아왔다.

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam){
 HDC hdc;
 PAINTSTRUCT ps;
 switch(iMessage){
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  Rectangle(hdc,10,10,400,100);
  EndPaint(hWnd,&ps);
 }

 return (DefWindowProc(hWnd,iMessage,wParam,lParam));

}

어디서 많이 본 코드가 아닌가?

그냥 간단하게 사각형을 그리는 코드가 되겠습니다.

이번에 할 것은 면을 다른 색으로 바꾸어보자.

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam){
 HDC hdc;
 PAINTSTRUCT ps;
 HBRUSH testbrush,savebrush;
 switch(iMessage){
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  testbrush=(HBRUSH)GetStockObject(GRAY_BRUSH);
  savebrush=(HBRUSH)SelectObject(hdc,testbrush);

  Rectangle(hdc,10,10,400,100);
  SelectObject(hdc,savebrush);
  EndPaint(hWnd,&ps);
 }

 return (DefWindowProc(hWnd,iMessage,wParam,lParam));

}

일단은 브러시 핸들을 저장할 변수를 선언하는데 하나는 사용할변수 하나는 임시 저장할 변수.

이렇게 만들어둡니다.

GetStockObject 함수로 회색 브러시를 얻되 hbrush에 형 변수에 대입하기위해 캐스팅을 했다.

SelectObject 가 리턴하는 값은 새로 선택된 오브젝트 이전에 선택되어있던 같은 종류의 오브젝트의 핸들이다.

오브젝트 핸들이다. 예를들어 펜을 선택하면 이전에 쓰던 펜을 브러쉬라면 이전에 쓰던 브러쉬이다.

이해가 안된다면 코드를 잠깐 더 수정해서.

 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  testbrush=(HBRUSH)GetStockObject(GRAY_BRUSH);
  savebrush=(HBRUSH)SelectObject(hdc,testbrush);
  Rectangle(hdc,10,10,400,100);
  SelectObject(hdc,savebrush);
  Rectangle(hdc,10,200,400,100);
  SelectObject(hdc,testbrush);
  Rectangle(hdc,10,300,400,200);

  EndPaint(hWnd,&ps);
 }

이렇게 바꿔보길 바란다.

그런데 왜 이렇게 이전것을 저장해두어야하는지는 차후에 설명하겠다.

참고로 결과는


이렇게 결과가 나올것이다.