비트교육/API

API(7) - realtime 방식과 button ,setTimer

ballde 2020. 9. 5. 12:05

이번에는 realtime 방식과 button ,setTimer을 해보겠습니다. 

들어가기에 앞서

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,                 // 응용 프로그램의 고유 아이디   중요!!
                     _In_opt_ HINSTANCE hPrevInstance,          //
                     _In_ LPWSTR    lpCmdLine,                  //
                     _In_ int       nCmdShow)                   // 윈도우의 초기 상태 지정 

WinMain의 인수에 대한 것입니다.            

마지막 인수 nCmdShow 를 보시면 

 ShowWindow(hWnd, nCmdShow);
 UpdateWindow(hWnd);

밑에 코드에 이것이 있습니다. nCmdShow 는 그냥 초기상태 값이라고 보면되는데 

howWindow(hWnd, SW_SHOWDEFAULT);                   //SW_SHOWDEFAULT  이것도 디버깅 하면 10 -> 즉 ncmdSHow는 default값
UpdateWindow(hWnd);                                 //WM_PAINT를 띄워주는 역할 invalidate()(큐안에들어감)하고 비슷한데 updatewindow는 
                                                        //큐안에 안들어감  while문 안에 들어가기전에 로딩화면 초기화 해주는 역할 

SHOWDEFAULT 값과 같습니다. (SHOWDEFULT값 -10) 

그리고 UpdataeWindow는 전시간에 배운 InvalidateRect()와 비슷하게 WM_PAINT를 발생시켜주는 함수입니다. 

하지만 UpdataeWindow은 큐에 들어가지 않아서 메세지 처리를 안하기 때문에 while문에 접근 하기 전에 초기화해주는 함수라고 보면 될 것같습니다. 

그리고 realtime방식입니다. 

    bool done = FALSE;
    while (!done)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))                 //noneblocking 메세지 큐에 메세지전달
        {
            if (msg.message == WM_QUIT)                               //메세지가 종료였다면 true로 while문 빠져나감 
                done = TRUE;
            else {
                TranslateMessage(&msg);                               //
                DispatchMessage(&msg);
            }
        }
        else {

            //변수 갱신만 전문적으로 하는 함수 
            //그리기와 관련된 함수                   rendering 함수  ---> InvalidateRect() 함수  
        }
    }

realtime방식은 blocking 즉 멈추는경우 없이 동작하는 경우입니다.

즉 메세지가 들어오면 메세지 처리를 하고 아니면 else로 보내서 다른 처리를 하게 됩니다. 

이런경우 변수 갱신이나  , rendering 함수를 많이 else부분에 넣습니다. 

 

이제 버튼 만드는 방식을 보겠습니다. 

WndPoc에 WM_CREATE 케이스를 만들어서 버튼을 넣어보겠습니다.

HWND hBtn1;            //전역함수로
case WM_CREATE:
    {
        //MessageBox(0, TEXT("WM_CREATE"), TEXT("WMCREATE"), MB_OK);
        hBtn1 = CreateWindowW(
            TEXT("BUTTON"),                               //예약어 COMBOBOX, EDIT 등의 종류 
            TEXT("호랑이1"),
            WS_VISIBLE | WS_CHILD | WS_BORDER,   // BS_DEFPUSHBUTTON,   --> 윈도우의 스타일 설정
            0, 0,                              //윈도우 위치 
            100, 50,                             //모양 크기    
            hWnd,                                //부모 
            (HMENU)1000,                         //어떤걸 눌렀는지 식별해주는 번호   --> wParam
            hInst,                               //인스턴스 전달 
            NULL);                               //
            }

이렇게 뜨게 됩니다. 중요한건 (HMENU)1000부분에서 식별해주는 것이 디버깅을 하면 wParam으로 가는 것을 알 수있습니다. 그러면 버튼을 클릭했을 경우 어떠한 발생을 일으킬 수 있다는 것을 알 수 있습니다 .

그리고 버튼 클릭했을 경우 WM_COMMAND에 함수 작성을 해줍니다. 

 

버튼 3개만들어주시고 

case WM_CREATE:
    {
        //MessageBox(0, TEXT("WM_CREATE"), TEXT("WMCREATE"), MB_OK);
        hBtn1 = CreateWindowW(
            TEXT("BUTTON"),                               //예약어 COMBOBOX, EDIT 등의 종류 
            TEXT("호랑이1"),
            WS_VISIBLE | WS_CHILD | WS_BORDER,   // BS_DEFPUSHBUTTON,   --> 윈도우의 스타일 설정
            0, 0,                              //윈도우 위치 
            100, 50,                             //모양 크기    
            hWnd,                                //부모 
            (HMENU)1000,                         //어떤걸 눌렀는지 식별해주는 번호   --> wParam
            hInst,                               //인스턴스 전달 
            NULL);                               //

       hBtn2 = CreateWindowW(
            TEXT("BUTTON"), TEXT("호랑이2"),
            WS_VISIBLE | WS_CHILD | WS_BORDER,   
            0, 50, 100, 50,                                 
            hWnd,                               
            (HMENU)2000,                         
            hInst, NULL);

       hBtn3 = CreateWindowW(
            TEXT("BUTTON"), TEXT("호랑이3"),
            WS_VISIBLE | WS_CHILD | WS_BORDER,
            0, 100, 100, 50,
            hWnd,
            (HMENU)3000,
            hInst, NULL);
    }
case WM_COMMAND:
    {
        switch (wParam)
        {
        case 1000:
        {
            //ShowWindow(hBtn3, false);
            //EnableWindow(hBtn3, false);
            //SetWindowText(hBtn3, TEXT("고양이"));
            //MessageBox(hWnd, TEXT("id :1000 "), TEXT("h"), MB_OK);
           

        }
        break;
        case 2000:
        {
            //ShowWindow(hBtn3, true);
            //EnableWindow(hBtn3, true);
            //SetWindowText(hBtn3, TEXT("독수리"));
            //MessageBox(hWnd, TEXT("id: 2000 "), TEXT("h"), MB_OK);
           
           
        }
        break;

showWindow ,EnableWindow ,SetWindowText 등을 나타낼 수 있습니다. 

showWindow는 hBtn3을 true -나타내준다. false - 없애준다. 

SetWindowText는 Text를 써주는 것입니다. 

EnEnableWindow -hBtn3을 true - 사용가능 false - 사용불가능 

이번에는 SetTimer를 알아보겠습니다. 

HANDLE hTimer = (HANDLE)SetTimer(hWnd, 123, 1000, NULL);          //1초는 1000ms -> WM_TIMER을 발생시킴 

SetTimer(주체, ID, 시간 간격 ,null)

그리고 1000->1초입니다.   

SetTimer는 WM_TIMER을 발생시키므로 WM_TIMER을 설정해주어야 합니다. 

case WM_TIMER : 
    {
        switch (wParam) {
        case 123:
        {
            WCHAR Str[32];
            static int ct = 0;
            wsprintf(Str, TEXT("fisrt Timer: %d\n"), rand()%100);
            OutputDebugString(Str);
        }
        break;
        case 456: 
        {
            WCHAR Str[32];
            static int ct = 0;
            wsprintf(Str, TEXT("second Timer: %d\n"), ct++);
            OutputDebugString(Str);
        }

아까 설정해준 id 또한 wParam으로 가기 때문에 위 코드와 같이 나누어 주면 됩니다.  

 

 KillTimer(hWnd, 123);

그리고 SetTimer을 했으면 반드시 꺼주어야 합니다.