본문 바로가기
코스웨어/15년 스마트컨트롤러

2015.11.16 -권오민- WinAPI-3일차

by 알 수 없는 사용자 2015. 11. 16.
728x90
반응형

API

◉4-1. 입력

●4-1-라. TranslateMessage

- 키보드에서 A키를 눌렀다가 뗐다고 가정하자.

        - WM_KEYDOWN, WH_CHAR, WM_KEYUP이 순서대로 발생한다.

        - WM_CHAR은 WM_KETDOWN에 의해 추가로 발생하는 메시지이다.

                - GetMessage는 메시지 큐에서 메시지를 꺼내와서 TranslateMessage로 넘겨준다.

                        - TranslateMessage는 WM_KEYDOWN인지와 눌려진 키가 문자키인지 검사한다.

                                - 조건이 맞을 경우 WM_CHAR 메시지를 만든다.

                                - 맞지 않거나 문자입력이 아닐 경우 아무것도 하지 않는다.

                                        - DispatchMessage에 의해 WndProc으로 보내진다.

◉4-2. 마우스 입력

●4-2-가. Mouse

- 키보드에서 wParam과 lParam을 통해 정보를 받아오듯이 마우스도 정보를 받을 수 있다.

        - lParam을 통해 좌표를 확인할 수 있다.

        - 창을 기준으로 처리된다.

                - 절대 좌표가 아니다.

        - wParam에서 눌러져 있는 키를 확인할 수 있다.


- 소스

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  
static int x;
  
static int y;
  
static BOOL bnowDraw = FALSE;
  
switch (iMessage)
  {
   
 case WM_LBUTTONDOWN:
      x 
= LOWORD(lParam);
      y 
= HIWORD(lParam);
      bnowDraw 
= TRUE;
      
return 0;
    
case WM_MOUSEMOVE:
      
if (bnowDraw == TRUE)
      {
        hdc 
= GetDC(hWnd);
        MoveToEx(hdc, x, y, NULL);
        x 
= LOWORD(lParam);
        y 
= HIWORD(lParam);
        LineTo(hdc, x, y);
        ReleaseDC(hWnd, hdc);
      }
      
return 0;
    
case WM_LBUTTONUP:
      bnowDraw 
= FALSE;
      
return 0;
    
case WM_DESTROY:
      PostQuitMessage(
0);
      
return 0;
  }
  
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

- 결과


- 가로, 세로의 한계가 존재한다.

        - X의 좌표는 0000 FFFF와 비트 연산한다.

        - Y의 좌표는 >>16 쉬프트한다.

- BOOL이 실제로 존재하지는 않는다.

        - define되어 있다.

        - window.h를 include하면 사용 가능하다.

●마우스의 좌표 출력하기

- 마우스의 좌표 출력하기

- 유니코드 인식 함수들은 표준 함수와 이름이 비슷하되 앞에 l자가 하나 더 붙는다는 것만 다르며, 운영체제가 제공하는 API함수이므로 별도의 용량을 차지하지 않는다는 장점이 있다.

- 소스

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  
static int x;
  
static int y;
  
static WCHAR wcBuffer[100];

  
switch (iMessage)
  {
    
case WM_PAINT:
      hdc 
= BeginPaint(hWnd, &ps);
      SetTextAlign(hdc, TA_CENTER);
      
TextOut(hdc, 100, 100, wcBuffer, lstrlen(wcBuffer));
      EndPaint(hWnd, 
&ps);
      
return 0;
    
case WM_MOUSEMOVE:
      x 
= LOWORD(lParam);
      y 
= HIWORD(lParam);
      wsprintf(wcBuffer, L"x는 %d, y는 %d이다.", x, y);
      InvalidateRect(hWnd, NULL, TRUE);

     
 return 0;
    case WM_DESTROY:
      PostQuitMessage(0);
      return 0;
  }
  return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

 

- 결과





●4-2-나. 더블클릭

- 윈도우는 더블클릭에 대한 메시지를 지원하지 않는다.

        - 더블클릭용 Flag를 추가해준다.

                - WndClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

        - 더블클릭을 검출하는 데는 실행시간의 감소가 요구된다.

- 소스

    case WM_LBUTTONDBLCLK:
      wcBuffer[
0= 0;  //wcBuffer을 지운다.
      InvalidateRect(hWnd, NULL, TRUE);
      
return 0;

- 결과


4-3. 타이머

●4-3-가. 시계

- WM_CREATE

        - 창이 만들어질 때 한번만 동작한다.

- SetTimer

        - 1. 윈도우 핸들러

        - 2. 타이머 번호

                - 여러개를 만들 수 있다.

        - 3. 시간(ms)

                - 1000 : 1초마다 동작

        - 4. 함수주소

                - 적지 않으면, WM_TIMER라는 메시지만 생성된다.

- WM_TIMER

        - time

                - 현재 시간을 초로 가지고 있다.

        - ctime

                - 문자열로 바꿔준다.

- WM_DESTROY

        - KillTimer

                - 타이머 번호를 입력해서, 닫아주어야 한다.

                        - 일치해야 닫아진다.

- 소스

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
 
 SYSTEMTIME st;
  
static TCHAR sTime[128];

  
switch (iMessage)
  {
    
case WM_CREATE:
      SetTimer(hWnd, 1, 1000, NULL);
      SendMessage(hWnd, WM_TIMER, 1, 0);
      return 0;
    case WM_TIMER:
      GetLocalTime(&st);
      wsprintf(  sTime
            , TEXT("현재 시간은 %d년 %d월 %d일 %d:%d:%d입니다.")
            , st.wYear
            , st.wMonth
            , st.wDay
            , st.wHour
            , st.wMinute
            , st.wSecond);
      
InvalidateRect(hWnd, NULL, TRUE);
      return 0;
    case WM_PAINT:
      hdc = BeginPaint(hWnd, &ps);
      TextOut(hdc, 100, 100, sTime, lstrlen(sTime));
      EndPaint(hWnd, &ps);
      return 0;
    case WM_DESTROY:
      KillTimer(hWnd, 1);

      PostQuitMessage(
0);
      
return 0;
  }
  
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

- 결과

●4-3-나. SendMessage

- 실행시킨 직후에 출력이 되지 않는다.

        - 문제는 WM_CREATE

                - SetTimer에서 주기를 1초로 하여 실행 후에 1초가 지나야 출력이 된다.

- 강제로 메시지를 발생시킨다.

- WM_TIMER

        - WM_TIMER 안에서 새로운 스위치 문을 만든다.

- 소스

   static RECT rt = { 100100400120 };

  
switch (iMessage)
  {
    
case WM_CREATE:
      SetTimer(hWnd, 
11000, NULL);
      SendMessage(hWnd, WM_TIMER, 1, 0);
      return 0;
    
case WM_TIMER:
        InvalidateRect(hWnd, 
&rt, TRUE); //부분 무효화

- 결과



●4-3-다. 두 개의 타이머

- 타이머는 한꺼번에 여러 개를 설치하여 사용할 수도 있다.

- 타이머를 2개 사용한 예제

        - 1번 Timer는 현재 시간을 계속 출력한다.

        - 2번 Timer는 5초 간격으로 메시지 박스를 출력한다.

- 소스<1>

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  SYSTEMTIME st;
  
static TCHAR sTime[128];
  
static RECT rt = { 100100500120 };

  
switch (iMessage)
  {
    
case WM_CREATE:
      SetTimer(hWnd, 1, 1000, NULL);
      SetTimer(hWnd, 2, 5000, NULL);

      SendMessage(hWnd, WM_TIMER, 
10);
      
return 0;
    
case WM_TIMER:
      GetLocalTime(
&st);
      wsprintf(sTime
        , TEXT(
"지금 시간은 %d:%d:%d입니다")
        , st.wHour
        , st.wMinute
        , st.wSecond);
      
switch (wParam)
      {
        case 1:
          InvalidateRect(hWnd, &rt, TRUE);
          break;
        case 2:
          MessageBox(hWnd, L"5초가 지났습니다.", L"Double Timer", MB_OK);
          break;
      }      

      
return 0;
    
case WM_PAINT:
      hdc 
= BeginPaint(hWnd, &ps);
      TextOut(hdc, 
100100, sTime, lstrlen(sTime));
      EndPaint(hWnd, 
&ps);
      
return 0;
    
case WM_DESTROY:
      KillTimer(hWnd, 
1);
      KillTimer(hWnd, 
2);
      PostQuitMessage(
0);
      
return 0;
  }
  
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

- 소스<2>

long FAR PASCAL WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  time_t mytime;
  
static HANDLE hTimer, hTimer2;
  
static char *str;
  
static RECT rt={100,100,400,120};
  
switch(iMessage) {
  
case WM_CREATE:
    hTimer
=(HANDLE)SetTimer(hWnd,1,1000,NULL);
    hTimer2
=(HANDLE)SetTimer(hWnd,2,5000,NULL);
    str
="";
    SendMessage(hWnd, WM_TIMER, 
10);
    
return 0;
  case WM_TIMER:
    
switch (wParam) {
    
case 1:
      time(
&mytime);
      str
=ctime(&mytime);
      InvalidateRect(hWnd,
&rt,TRUE);
      
break;
    
case 2:
      
MessageBox(hWnd, L"5초가 지났습니다.", L"Double Timer", MB_OK);
      
break;
    }

    
return 0;
  
case WM_PAINT:
    hdc
=BeginPaint(hWnd,&ps);
    TextOut(hdc,
100,100,str,strlen(str)-1);
    EndPaint(hWnd,
&ps);
    
return 0;
  
case WM_DESTROY:
    KillTimer(hWnd,
1);
    KillTimer(hWnd,
2);
    PostQuitMessage(
0);
    
return 0;
  }
  
return(DefWindowProc(hWnd,iMessage,wParam,lParam));

- 결과



●4-3-라. 콜백함수

- 운영체제에 의해 호출되는 프로그램 내부의 함수.

        - 오직 운영체제만이 호출할 수 있다.

- SetTimer의 4번째 인자에 함수가 인자로 들어있다면, 정해진 시간마다 함수를 실행한다.

        - 앞에서 언급 했듯이 NULL을 입력하면 WM_TIMER 메시지가 호출된다.

- 타이머 메시지를 받을 때 마다 조금씩 나누어 하는 것이 좋다.

- 타이머 메시지 보다 정확한 시간에 호출된다.

- 소스

void CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
  HDC hdc;
  
int i;
  hdc 
= GetDC(hWnd);
  
for (i = 0; i < 100; ++i)
  {
 
   SetPixel(
          hdc, rand()%100, rand()%100,
          RGB(rand()%256, rand()%256, rand()%256,)
        );

    ReleaseDC(hWnd, hdc);
  }
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
  
switch (iMessage)
  {
    
case WM_CREATE:
      
SetTimer(hWnd, 1100, (TIMERPROC)TimerProc);
      
return 0;
    
case WM_DESTROY:
      KillTimer(hWnd, 
1);
      PostQuitMessage(
0);
      
return 0;
  }
  
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

- 결과


        - 예제에서는 WM_PAINT가 없으므로 저장이 되지 않아 지워진다.

◉4-4. 윈도우 관리 메시지

●4-4-가. 생성 및 파괴

- 윈도우와 관련된 메시지중 가장 간단한 메시지는 윈도우가 생성될 대 보내지는 WM_CREATE와 윈도우가 파괴될 때 보내지는 WM_DESTROY 2가지가 있다.

- 위의 메시지 대신 사용할 수 있는 방법은 WinMain에서 직접 초기화와 종료 처리를 해주는 방법이 있다.

●4-4-나. 작업영역

- GetClientRect

- 소스

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  
static RECT rt;
  
static int x;
  
static int y;
  
static WCHAR wcBuffer[100];
  
switch (iMessage)
  {
    
case WM_CREATE:
      GetClientRect(hWnd, &rt);
      
return 0;
    
case WM_PAINT:
      hdc 
= BeginPaint(hWnd, &ps);
      SetTextAlign(hdc, TA_CENTER);
      TextOut(hdc, rt.right/2, rt.bottom/2, TEXT("Center String"), 13);
      TextOut(hdc, 
100100, wcBuffer, lstrlen(wcBuffer));
      EndPaint(hWnd, 
&ps);
      
return 0;
    
case WM_MOUSEMOVE:
      x 
= LOWORD(lParam);
      y 
= HIWORD(lParam);
      wsprintf(wcBuffer, TEXT(
"x는 %d, y는 %d이다."), x, y); 
      InvalidateRect(hWnd, NULL, TRUE);
      
return 0;
    
case WM_DESTROY:
      PostQuitMessage(
0);
      
return 0;
  }
  
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

- 결과

●4-4-다. WM_SIZE

- 윈도우의 창 크기를 변경 할 때마다 호출된다.


- 6교시만 하고 가게되어 정리는 여기까지 입니다 ㅠ.

728x90