마우스를 좌클릭을 이용해서 네모를 찍어낼거다.
좌클릭을 하려면 마우스클릭에 관한 메시지를 프로시져가 받아온다.
좌표를 얻으려면 WM_LBUTTONDOWN 메시지가 전달될때,
메세지 내에 lParam
에는 마우스 클릭 좌표가 같이 전달된다.
int x = lParam & 0x0000FFFF;
int y = (lParam>>16) & 0x0000FFFF;
int x = LOWORD(lParam);
int y = HIWORD(lParam);
#include <windowsx.h>
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
코드구현
마우스커서에서 네모가 그려지지만, 커서를 중심으로 네모를 그리고싶다면 네모가 그려지는 함수를 이렇게 한번 만들어보자
Rectangle(h_dc, cursor_x-50, cursor_y-50, cursor_x+50, cursor_y+50);
윈도우프로그램의 창을 옮기다보면 안보일 화면밖을 나가서 안보일수도 있다.
이렇게 안보일때 WM_PAINT라는 메시지를 메시지큐에 전달하여 Window에 그림을 다시그려야함.
저 주황색으로 슥삭 한 곳이 클라이언트 영역이다.
GetDC로 DC핸들러를 가져다 그림을 열심히 그려도, 특정 상황에 빠지면 그림은 지워지고 복구도 안된다.
무효화 영역
복구는 어떻게 하냐?
WM_PAINT
메시지를 받아서 처리한다.LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM, LPARAM lParam)
{
if(uMsg == WM_PAINT){
// 윈도우의 일부 또는 전부의 그림을 그려야하는 경우.
} else if(uMsg == WM_DESTROY) PostQuitMessage(0);
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
BeginPaint()
함수를 사용한다.PAINTSTRUCT 구조체
// WinUser.h
typedef struct tagPAINTSTRUCT{
HDC hdc;
BOOL fErase; // BeginPaint 함수로 얻은 DC핸들 값
RECT rcPaint; // 윈도우의 기본 배경을 다시 그릴지 여부
BOOL fRestore; // 다시 그려야할 영역 정보
BOOL fInUpdate; // OS에 의해 내부적으로 사용됨
BOOL fIncUpdate; // OS에 의해 내부적으로 사용됨
BYTE rgReserved[32]; // OS에 의해 내부적으로 사용됨
} PAINTSTUCT
BeginPaint 함수를 사용하여 DC 얻기
PAINTSTRUCT ps;
Hdc h_dc = BeginPaint(hWnd, &ps);
EndPaint 함수를 사용하여 DC 반환
EndPaint(hWnd, &ps);
이제 WndProc함수에 이렇게 추가하면 됨
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if(uMsg == WM_PAINT)// 윈도우의 일부 혹은 전부 그림을 그려야할 경우.
{
PAINTSTRUCT ps;
HDC H_DC = BeginPaint(hWnd, &ps);
// 그리는 작업!!!
EndPaint(hWnd, &ps);
// WM_PAINT 메시지를 직접 처리했지 때문에 DefWindProc 함수가
// 호출되지 않게 이 시점에 WndProc 함수를 종료한다.
return 0;
} else if(uMsg = WM_DESTORY) PostQuitMessage(0);
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
WM_PAIT 메시지에서 사각형 그리는 코드를 추가한 경우
PAINTSTRUCT ps;
HDC h_dc = BeginPaint(hWnd, &ps);
// h_dc를 이용하여 사각형을 그린다.
Rectangle(h_dc, 10, 10, 100, 100);
EndPaint(hWnd, &ps);
실제 프로그래밍 시에는 처리작업순위를 보여주는작업보다 중요하게 본다.
윈도우 운영체제의 메시지 처리 방식
WM_PAINT
와 같은 낮은 우선순위들을 Flag메시지
아닌, 메시지 테이블
로 관리함.절대 WM_PAINT 메시지루틴에서는 GetDC를 사용하지 말라!!!!
CreateWindow() 를 사용하여 윈도우 생성을 할 수 있음.
근데 이 윈도우는 OS가 관리하기 때문에 접근이 어려움.
개발자가 추가적인 접근을 할 수 있도록 받을 수 있는 메시지가 WM_CREATE
메시지 이다. 이 메시지를 받으면 작업하면됨.
WM_CREATE
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if(uMsg == WM_CREATE){
// 새로운 윈도우가 만들어졌고 출력직전 상태.
return 0;// 정상적으로 작업이 완료됨.
} else if(uMsg == WM_DESTROY) PostQuitMessage(0);
return DefWindowProc(hWnd, uMsgm wParam, lParam);
}
WM_CREATE메시지와 함께 전달되는 wParam
은 별내용없고, lParam
에는 윈도우 생성시 사용된 설정정보의 시작주소가 저장됨
CREATESTRUCT
구조체로 형변환 하여 사용하면 됨LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if(uMsg == WM_CREATE){
// 새로운 윈도우가 만들어졌고 출력직전 상태.
CREATESTRUCT *p_create_type = (CREATESTRUCT *)lParam;
// p_create_type을 사용하여 윈도우 생성정보를 사용하면됨.
return 0;// 정상적으로 작업이 완료됨.
} else if(uMsg == WM_DESTROY) PostQuitMessage(0);
return DefWindowProc(hWnd, uMsgm wParam, lParam);
}
윈도우가 최초 생성될 때 한번만 전달하는 메시지이다.
프로그램의 기본적인 초기화 작업 용도로 사용됨.
우리가 많이 사용하는 비트맵은 DDB 이다.
비트패턴에 형식이 조금만 틀려도 큰일나는 민감한 친구들을 다룬다는 말임.
BitBlt()
: Windows OS에서 제공하는 비트맵객체의 비트패턴을 다른 비트맵에 복사하는 API 함수DC 핸들러를 사용해서 비트맵의 그림을 복사해보자.
#include <wingdi.h>
#include <gdi32.lib>
BOOL BitBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight,
HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop);
BitBlt() 매개변수
BitBlt() 함수는 하드웨어 지원을 받아서 사용해서 성능도 굉장히 좋다.
BitBlt 함수를 이용한 예제
HDC h_screen_dc = ::GetDC(NULL); // 모니터 전체 화면용 DC를 얻음
HDC h_dc = ::GetDC(m_hWnd); // 현재 윈도우용 DC를 얻는다.
BitBlt(h_dc, 10, 10, 500, 300, h_screen_dc, 0,0,SRCOPY);
::ReleaseDC(m_hWnd, h_dc); // 사용하던 DC를 해제한다.
::ReleaseDC(NULL, h_screen_dc); // 사용하던 DC를 해제한다.
DC를 Window에 만들어진 DC만 사용가능한게 아님. CreateDC를 이용해서 DC를 직접만들어 사용가능함. 그 DC를 좀더 쉽게 만들기 위해 사용하는 함수.
HDC h_dc = ::GedDC(m_hWnd); // m_hWnd 윈도우에 그림을 그리는 DC
HDC h_screen_dc = ::GetDC(NULL); // 화면 전체에 그리는 DC
여태 이렇게 GetDC로 DC를 얻어와서 그려왔음.
CreateCompatibleDC()
: DC의 특성 대부분을 가지고있지만, 출력장치와 연결안된 DC를 생성하는 함수
HDC CreateCompatibleDC(HDC hdc);
DeleteDC()
로 제거해야함HDC h_c = ::GetDC(m_hWnd); // 윈도우에 그림을 그리는 DC를 얻는다.
HDC h_mem_dc = CreateCompatibleDC(h_dc);// h_dc와 호환되는 DC를 생성
// h_mem_dc와 연결된 비트맵에 사각형을 그린다. 이그림은 출력되지 않음
Rectangle(h_mem_dc, 10, 10, 100, 100);
DeleteDC(h_mem_dc);
::ReleaseDC(m_hWnd, h_dc);
CreateCompatibleDC()를 이용해서 얻은 DC는비트맵 객체가 연결은 되어있는데 제대로된 객체가 아님.
CreateCompatibleDC()로 생성한 DC를 사용하려면 비트맵 객체를 만들어서 연결해야함
HDC h_dc = ::GetDC(m_hWnd);
HDC h_mem_dc = CreateCompatibleDC(h_dc);
// h_dc 와 호환되는 비트맵을 폭 400, 높이 300의 크기로 만듦
HBITMAP h_mem_bmp = CreateCompatibleBitmap(h_dc, 400, 300);
// h_mem_dc에 h_mem_bmp을 연결함.
SelectObject(h_mem_dc, h_mem_bmp);
// h_mem_dc와 연결된 h_mem_bmp에 사각형을 그린다. 이그림은 출력안됨
Rectangle(h_mem_dc, 10, 10, 100, 100);
DeleteObject(h_mem_bmp);
DeleteDC(h_mem_dc);
::ReleaseDC(m_hWnd, h_dc);
더블 버퍼링(Duble uffering)