'programing'에 해당되는 글 29건

  1. 2010.07.17 WinApi input WM_CHAR
  2. 2010.07.17 WinApi MessageBox
posted by nsakura 2010. 7. 17. 22:08

WM_CHAR

자 친구들은 C언어하면 생각나는 입력함수가 뭐가 있는가? scanf,getch,gets 등의 함수들이 기억날것이다.

그런데 생각해보자 c언어에서 사용자 입력함수가 호출되는 시점에서 프로그램은 입력을 기다린다

즉 이 시간동안은 프로그램이 대기 한다.

그런데 윈도에서 어떤가. 입력을 기다린다고 프로그램 전체가 멈추는 경우가 있는가?

무슨 말인지 이해가 안간다면 당장 메모장을 켜놓고. 찾기 기능을 켜놓고 메모장에 글을 적어보자.

그럼 이해가 될것이다.

메모장을 예를들어서 이야기 하면 찾기기능에 입력은 안하지만 본문에 입력을 하고있다고 치자.

계속해서 프로그램은 돌아가는 중이고 탐색에서는 입력을 기다리는것이다.

탐색에서 입력이 되면 포커스를 가진 프로그램에서  메세지를 던져주면 되는 것이다. 그 것이 (WM_CHAR, WM_KEYDOWN)이다.

여기서 포커스는 입력 초점이라고 생각하면 된다.

그럼 한번 예제를 풀어보도록 하죵

#include <windows.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_Inst;
LPCTSTR winName=TEXT("GFP INPUT");

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd){
 HWND hWnd;
 WNDCLASS WndClass;
 MSG Message;
 g_Inst=hInstance;

 WndClass.cbClsExtra=0;
 WndClass.cbWndExtra=0;
 WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
 WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
 WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
 WndClass.hInstance=hInstance;
 WndClass.lpfnWndProc=WndProc;
 WndClass.lpszClassName=winName;
 WndClass.lpszMenuName=NULL;
 WndClass.style=CS_HREDRAW|CS_VREDRAW;
 RegisterClass(&WndClass);

 hWnd=CreateWindow(winName,winName,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL);

 ShowWindow(hWnd,nShowCmd);

 while(GetMessage(&Message,NULL,0,0)){
  TranslateMessage(&Message);
  DispatchMessage(&Message);
 }
 return (int)Message.wParam;

}

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam){
 HDC hdc;
 PAINTSTRUCT ps;
 static TCHAR str[256];
 int len;
 
 switch(iMessage){
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 case WM_CHAR:
  len=lstrlen(str);
  str[len]=(TCHAR)wParam;
  str[len+1]=0;
  InvalidateRect(hWnd,NULL,FALSE);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  TextOut(hdc,100,100,str,lstrlen(str));
  EndPaint(hWnd,&ps);
  return 0;
 }
 return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}

WM_CHAR 메세지에서 키보드에서 입력한 문자를 모은다.

str을 왜 정적으로 선을 했냐면 이유는 간단하다. 그냥선언되면 프록 함수가 다시 호출될때 변수가 초기화가 되기 때문이다.

그래서 정적으로 선언을 한것이다. 이해가 잘안되면 로컬변수와 전역변수에 대해 공부해보기 바란다.

static이 싫다면 그냥 전역변수로 선언해도 된다.

그런데. 이 프로그램을 보면 잠깐 생각해볼 문제가 있지 않나?

왜 문자을 입력해서 출력하는데 입력받은 문자를 저장을 하느냐?

이다..

이유는 문자를 입력을 받고 바로 출력을 하는게 아니라 입력과 출력을 할 시점이 분리되어있기 때문이다.

만일 입력과 출력을 분할하지 않으면 우리가 몇일전 글씨 출력에 일어나는 현 프로그램이 다른 프로그램 아래 깔렸을때(언커버)

글씨가 지워지는 현상 발생하기 때문이다. 그렇다면 다른 방법은 없는 것인가? 방법은 있다 그 방법은 차후에 설명하겠다.


WM_CHAR 메세지는 입력된 문자의 코드를 wParam으로 전달한다.

그래서    str[len]=(TCHAR)wParam; 이렇게 되는 것이다.

str[len+1]=0; 이부분은 문자열의 끝을 표현한것이다.

출력하는 부분은 DC를 얻어서 출력하는 방법인데.

WM_PAINT 부분이 담당한다. 그런데 이렇게만 쓴다고해서 자동으로 WM_PAPINT부분을 호출하지 않는다. 강제적으로 호출을 시켜야하는데.

InvalidateRect(hWnd,NULL,FALSE);

이 부분이 되겠다.

잠시 좀더 자세히 살펴보자

InvalidateRect는 강제적으로 WM_PAINT를 발생시키기위해 사용했다고했다. 그런데 전 예제를 잘 본사람이라면 WM_PAINT의 역활에 대해

언급 했었다. 바로 윈도 창을 다시그릴때 사용한다고 잠깐 언급을 했었다. 예를들어.


이런 상태라고 치자. 그렇다면 저기 겹쳐진 부분이 있는데 실제로는 카드 게임에는 무효화 영역이 있는 것이다.

이 상태에서 다시 그림판을 옮겨서 카드 게임을 100%다 보이게 했다. 그럼 카드게임 내부에서 WM_PAINT가 메세지를 받는데.

그럼 누가 보내준것일까? 바로 OS가 메세지를 던져주는것이다. "야 카드게임 너 윈도 다시 그려야해"

라고. 이건 외부적인 요인에 발생하는 변화는 이렇게 OS가 관여해주지만.

프로그램 내부의 변화는 OS가 관여하지 않는다. 왜냐하면 내부적인 프로그램의 주체는 프로그래머의 의해 결정이 되기 때문에

즉 OS가 판단을 할수가 없다는것이다. 그래서 관여를 안한다. 그래서 강제로 갱신을 해주기 위해서는 InvalidateRect

사용한다. 이 함수의 원형을 보자.

BOOL InvalidateRect(HWND hWnd, CONST RECT *lpRect, BOOL bErase);

첫 번째 인수는 무효화되는 대상을 말한다.

두 번째 인수 무효화할 영역을  지정하다 이 값을 NULL로 지정 하면 윈도우 전역이 무효화 된다.

무조건 NULL을 하게 되면 화면을 다시 그리는 시간이 다소 거릴수있다.[느끼지는 못하겠지만..]

세 번째 인수는 무효화 되기 전의 배경을 모두 지운후 다시 그릴 것인 아닌가 배겨을 지우지 않고 그릴 것인가를 지정한다.

잘 이해가 안된다고?

그렇다면 이렇게 테스트를 해보자

 case WM_CHAR:
  if((TCHAR)wParam==' '){
   str[0]=0; 
   }

  else{
   len=lstrlen(str);
   str[len]=(TCHAR)wParam;
   str[len+1]=0;
  }
  InvalidateRect(hWnd,NULL,TRUE);
  return 0;

이렇게 고쳐서.

InvalidateRect(hWnd,NULL,TRUE);

3번째 인자를 false로도 바꿔보고 true로도 한번 테스트를 해보자.

그럼 이해가 될 것이다.

위의 코드는 스페이스바를 누르면 모든 문자열을 지운다.

false로 하면.하면 덮어 씌어져서 써질것이다.

'Computer > Win API' 카테고리의 다른 글

WinApi 마우스 입력.  (0) 2010.07.18
WinApi WM_KEYDOWN  (0) 2010.07.18
WinApi MessageBox  (0) 2010.07.17
WinApi 여러가지 출력  (0) 2010.07.16
WinApi DrawText  (0) 2010.07.15
posted by nsakura 2010. 7. 17. 15:47

요즘 게임 말고 예전 게임을 생각을 해보자 저 MessageBox는 상당히 많이 나왔었다는 사실.

특히 게임을 종료할때 작은창이 뜨면서. "너님 종료할래얌?"

이라는 메세지가 뜨면서 확인 취소 버튼이있는 작은 창을 본적 있을 것이다.

오늘은 그것에 대해서 알아보도록 하자.

이번 코드도 상당히 간단하다.

#include <windows.h>

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_Inst;

LPCTSTR winName=TEXT("GFP MESSAGEBOX");

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nShowCmd){
 HWND hWnd;
 MSG Message;
 WNDCLASS WndClass;
 g_Inst=hInstance;

 WndClass.cbClsExtra=0;
 WndClass.cbWndExtra=0;
 WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
 WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
 WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
 WndClass.hInstance=hInstance;
 WndClass.lpfnWndProc=WndProc;
 WndClass.lpszClassName=winName;
 WndClass.lpszMenuName=NULL;
 WndClass.style=CS_HREDRAW|CS_VREDRAW;
 RegisterClass(&WndClass);

 hWnd=CreateWindow(winName,winName,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL);
 
 ShowWindow(hWnd,nShowCmd);

 while(GetMessage(&Message,NULL,0,0)){
  TranslateMessage(&Message);
  DispatchMessage(&Message);
 }


 return (int)Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam){
 switch(iMessage){
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 case WM_LBUTTONDOWN:
  MessageBox(hWnd,TEXT("메세지 박스 입니다,"),winName,MB_OK);
  return 0;
 }

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

}

메세지 박스 함수 원형을 자세히 살펴보자!

int MessageBox(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT nType);

첫 번째 인수 박스의 오너 윈도우

두 번째 인수 메세지 박스의 내용

세 번째 인수 메세지 박스의 제목

네 번째 인수 메세지 박스의 종류

 MB_ABORTRETRYIGNORE  Abort, Retry, Ignore 세 개의 버튼이 나타난다.
 MB_OK  OK 버튼 하나만 나타난다.
 MB_OKCANCEL  OK 버튼과 CANCEL 버튼이 나타난다
 MB_RETRYCANCEL  RETRY,CANCEL 버튼이 나타난다.
 MB_YESNO  YES,NO 두개의 버튼이 나타난다
 MB_YESNOCANCEL  YES,NO,CANCEL 세 개의 버튼이 나타난다.

다 사용해 보자!

본인은 간단하게
 
  case WM_LBUTTONDOWN:
  cnt++;
  if(cnt==7){
   cnt=1;
  }

  switch(cnt){
   case 1:
    MessageBox(hWnd,TEXT("MB_OK 메세지 박스 입니다,"),winName,MB_OK);
    return 0;
   case 2:
    MessageBox(hWnd,TEXT("MB_ABORTRETRYIGNORE 메세지 박스 입니다,"),winName,MB_ABORTRETRYIGNORE);
    return 0;
   case 3:
    MessageBox(hWnd,TEXT("MB_OKCANCEL 메세지 박스 입니다,"),winName,MB_OKCANCEL);
    return 0;
   case 4:
    MessageBox(hWnd,TEXT("MB_RETRYCANCEL 메세지 박스 입니다,"),winName,MB_RETRYCANCEL);
    return 0;
   case 5:
    MessageBox(hWnd,TEXT("MB_YESNO 메세지 박스 입니다,"),winName,MB_YESNO);
    return 0;
   case 6:
    MessageBox(hWnd,TEXT("MB_YESNOCANCEL 메세지 박스 입니다,"),winName,MB_YESNOCANCEL);
    return 0;

  }

위의 코드를 사용할때 cnt변수는 전역으로 설정되어있어야하며 초기화는 잊지말자.

위의 코드를 사용하면 마우스 버튼을 누를때마다 각 다른 메세지박스가 나온다.



팁으로 메지박스에 아이콘을 출력할수 있는데 nType 버튼종류와 아이콘 종류를 or연산으로 묵어서 사용이 가능하다

아이콘 값은 다음과 같다.

 MB_ICONEXCLAMATION,MB_ICONWARNING  삼각형에 느낌표
 MB_ICONINFORMATION,MB_ICONASTERISK  말꾸러미에 !표
 MB_ICONQUESTION  말꾸러미에 ?표
 MB_ICONSTOP,MB_ICONERROR,MB_ICONHAND  금지 표시

한번 해보자

 case WM_LBUTTONDOWN:
  MessageBox(hWnd,TEXT("메세지 박스 입니다,"),winName,MB_OK|MB_ICONINFORMATION);
  return 0;
 }


앞에서 보면 여러가지 버튼이 나왔는데 그 버튼에 대한 처리를 한번 해보자.

MB_YESNO를 사용한다고 치자 즉 YES와 NO에 각각 이벤트를 넣어보자.

어떻게 해야할것 인가?

역시 간단하다.

 case WM_LBUTTONDOWN:
  if(MessageBox(hWnd,TEXT("메세지 박스 입니다,"),winName,MB_YESNO|MB_ICONINFORMATION)==IDYES){
   MessageBox(hWnd,TEXT("YES를 눌렀음."),TEXT("YES"),MB_OK|MB_ICONINFORMATION);
   return 0;
  }
  else{
   MessageBox(hWnd,TEXT("NO를 눌렀음,"),TEXT("NO"),MB_OK|MB_ICONINFORMATION);
   return 0;
  }
 }

자 그럼 버튼에 대한 리턴값을 알아보자

 IDABOUT  about 버튼을 눌렀다.
 IDCANCEL  cancel 버튼을 눌렀다.
 IDIGNORE  ignore 버튼을 눌렀다.
 IDNO  no 버튼을 눌렀다.
 IDOK  ok 버튼을 눌렀다.
 IDRETRY  retry 버튼을 눌렀다.
 IDYES  yes 버튼을 눌렀다.

이때까지는 대부분 눈에 보이는 출력을 했다. 글씨를 보여준다던가 그림을 그린다던가.

그런식의 출력을 했는데 마지막으로 보이지 않는 출력을 하려고한다.

바로 소리!

함수 원형은

BOOL MessageBeep(UINT nType);

nType은 역시 메크로 정의가 되어있는데.

 0xffffffff  PC의 스피커를 통해 음을 낸다.
 MB_ICONASTERISK  Asterisk 비프음
 MB_ICONEXCLAMATION  Exclamation 비프음
 MB_ICONHAND  Hand 비프음
 MB_ICONQUESTION  Question 비프음
 MB_OK  시스템 디폴트 비프음

하지만 시스템이 정의한 소리가 아닌 진짜 소리를 내고 싶으면 PalySound함수를 사용해야하지만 이건 차후에

사용해보자



tip

윈도우 타이틀 바에문자열을 출력함 SetWindowText 함수가 있는데

이 함수는 디버깅 목적으로도 사용을 하니 알아보는것도 나쁘지 않다.

타이틀바에서 문자열을 잃을때는 GetWindowText 함수가 있다.







자 이로서 출력 부분은 끝을 내도록 하자.

다음 포스팅은 당연히 입력 부분을 해보자!

'Computer > Win API' 카테고리의 다른 글

WinApi WM_KEYDOWN  (0) 2010.07.18
WinApi input WM_CHAR  (0) 2010.07.17
WinApi 여러가지 출력  (0) 2010.07.16
WinApi DrawText  (0) 2010.07.15
WinApi DC 예제  (0) 2010.07.15