본문 바로가기

WinAPI

[WinAPI] 도형 그리기, 마우스 좌표

 case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps); //출력하기 위한 도구           
           
            //텍스트 출력 (x좌표,y좌표,텍스트,크기)
            TextOut(hdc, 50, 50, TEXT("win32"), 5);
            //사각형 출력 (왼쪽위좌표,오른쪽아래좌표)
            Rectangle(hdc, 100, 100, 200, 200);
            //원 출력 (왼쪽위좌표,오른쪽아래좌표)
            Ellipse(hdc, 100, 100, 200, 200);
            //선 그리기
            MoveToEx(hdc, 300, 100, NULL); //시작좌표
            LineTo(hdc, 400, 150); //끝좌표
            MoveToEx(hdc, 100, 400, NULL);//다른 선을 그릴 때마다 시작좌표 새로 설정해야 함
            LineTo(hdc, 200, 500);  
            EndPaint(hWnd, &ps);
        }
        break;

WM_PAINT는 화면을 그릴 때 호출된다. hdc에 출력할 윈도우 핸들을 설정한다. 그리고 텍스트, 사각형, 원, 선을 출력한다. 그 다음은 스타크래프트처럼 마우스를 드래그 할 때 사각형을 출력하도록 해보자.

 

struct _tagArea
{
    bool bStart;
    POINT ptStart;
    POINT ptEnd;
};

_tagArea g_tArea;

먼저 출력할 사각형의 시작점과 끝점, 그리고 드래그 중인지 확인하기 위한 bool변수를 가진 구조체를 하나 만들고

전역으로 구조체 타입의 객체를 선언한다.

 

 case WM_LBUTTONDOWN:
        //마우스 위치는 lParam에 들어오는데 32비트에 16비트씩 쪼개서 x,y값이 들어옴
        //LOWORD, HIWORD 매크로로 상위, 하위 16비트 값을 얻어올 수 있다.
        if (!g_tArea.bStart)
        {
            g_tArea.bStart = true;
            // 만약 lParam이 0x12345678
            g_tArea.ptStart.x = lParam & 0x0000ffff; // 설명 참고
            g_tArea.ptStart.y = lParam >> 16;         

            //강제로 WM_PAINT 메시지를 호출해주는 함수
            //두번째 인수는 갱신할 영역,NULL일 경우 전체화면 대상 갱신
            //3번 인자는 TRUE일경우 현재 화면 지우고 갱신, FALSE일 경우 안지움
            InvalidateRect(hWnd, NULL, TRUE);
        }
        break;

WM_LBUTTONDOWN은 마우스 왼쪽 버튼을 누를 때 호출된다. 누르면 드래그가 시작되는 것이므로 bStart를 true로 설정한다. 그리고 드래그의 시작점 좌표를 설정한다.  마우스 위치는 lParam에 들어온다. 32비트에 16비트씩 쪼개서 x,y 값이 들어오는데 먼저 lParam과 0x0000ffff를 &연산한다. 16진수 1비트는 이진수 4비트이기 때문에 16진수 0000ffff는 

0 16비트와 1 16비트로 이루어져있다. 그래서 0x12345678과 0000ffff를 &연산하면 5678이 된다. (마스크 오프)

그리고 lParam>>16은 16비트만큼 오른쪽으로 미는 것이므로  0x12345678 >> 16하면 1234가 된다. 그리고 InvalidateRect 함수를 이용해 WM_PAINT를 강제로 호출하고 화면을 갱신한다.

 

 case WM_MOUSEMOVE:
        if (g_tArea.bStart) 
        {
            g_tArea.ptEnd.x = lParam & 0x0000ffff; 
            g_tArea.ptEnd.y = lParam >> 16;
            InvalidateRect(hWnd, NULL, TRUE);
        }
        break;
    case WM_LBUTTONUP:
        if (g_tArea.bStart)
        {
            g_tArea.bStart = false;
            g_tArea.ptStart.x = lParam & 0x0000ffff; 
            g_tArea.ptStart.y = lParam >> 16;
            InvalidateRect(hWnd, NULL, TRUE);
        }
        break;

 

그리고 마우스 왼쪽 버튼을 누른 상태에서 움직일 시 끝좌표가 갱신되고 화면에 출력한다. 마우스 왼쪽 버튼을 떼면 드래그를 중지하고 마지막 마우스 좌표를 화면에 출력한다.

 

 case WM_KEYDOWN:
        //wParam에 어떤 키를 눌렀는지 들어옴
        switch (wParam)
        {
        case VK_ESCAPE:
            DestroyWindow(hWnd);
            break;
        }
        break;

WM_KEYDOWN은 키보드에 키를 입력할 때 호출된다. 입력한 키 값은 wParam에 저장된다. 

 

'WinAPI' 카테고리의 다른 글

[WinAPI] 더블 버퍼링  (0) 2022.01.20
[WinAPI] 삼각함수  (0) 2022.01.16
[WinAPI] 델타 타임  (0) 2022.01.16
[WinAPI] PeekMessage와 윈도우 창 크기 설정  (0) 2022.01.15
[WinAPI] 기본 윈도우 창  (0) 2022.01.15