- 음악과 나 -/『 짬 통 』

4월 16일.. 입력 뒷부분과.. 리소스 조금, 그리고 그래픽.

noon2dy 2006. 4. 16. 20:45

//*********************************************************
// 4월 16일 일요일 오후 3시 4분..

 

마우스 메시지는 lParam의 상위워드에 마우스 버튼이 눌러진 y좌표,
하위워드에 마우스 버튼이 눌러진 x좌표를 가지며,
좌표값검출을위해 HIWORD, LOWORD등의 매크로 함수를 사용함.
ex>
마우스 메시지가 발생한 위치의 좌표 ( x, y )
=> ( LOWORD( lParam ), HIWORD( lParam ) );

 

wParam. lParam..
둘다 32비트값이므로 메시지가 전달할 수 있는 부가정보는 총 64비트.
16비트 Windows때는 wParam은 16비트였고, lParam은 32비트였다.
(wParam의 w는 WORD라는뜻. lParam의 l은 LONG이라는 뜻 )
지금 WIN32에서는 둘 다 32비트이므로 w, l문자는 더이상 길이가 아닌
단순한 이름일뿐이다.


무효영역? 복습~
윈도우영역중 일부분이라도 다시 그려져야할필요가 있는 영역..?
이. 무효영역이 생기면 OS는 이 윈도우에게 WM_PAINT 메시지를 보내줘서
다시 그 영역을 그리도록 한다.
데이터의 변화가 있을때 OS측에서는 화면으로 출력해야되는지 내부적으로만 계산해야할것인지
모르기때문에 작업영역을 무효화시키지 않음.
그래서 윈도우의 모습을 변경시켰을때는 변경된 부분이 다시 그려질 수 있도록
강제로 무효화 시켜줘야된다. 이때 강제로 무효화시키기위해 사용되는함수가
InvalidateRect()함수다.


// BOOL InvalidateRect( HWND hWnd, CONST RECT *lpRect, BOOL bErase );
// hWnd -> 무효화의대상이되는윈도우( 다시 그려줘야할윈도우) 의 핸들.
// lpRect -> 무효화의 대상이되는 사각영역( NULL일경우 윈도우 전체 영역 )

 

 

화면 전체를 지우려면?
InvalidateRect함수를 호출해서 작업영역 전체를 무효화시켜주면된다.

 

 

윈도우클래스 구조체..
typedef struct tagWNDCLASSEXA {
    UINT        cbSize;
    /* Win 3.x */
    UINT        style;  -> 윈도우의 스타일정의
    WNDPROC     lpfnWndProc; -> 윈도우의 메시지처리함수 지정
    int         cbClsExtra; -> 특수목적에 사용되는 여분의 예약공간( 보통 0 )
    int         cbWndExtra; -> 특수목적에 사용되는 여분의 예약공간( 보통 0 )
    HINSTANCE   hInstance; -> 이 윈도우 클래스를 등록하는 프로그램의 번호
    HICON       hIcon;  -> 이 윈도우가 사용할 아이콘 지정( LoadIcon함수 사용 )
    HCURSOR     hCursor; -> 이 윈도우가 사용할 커서 지정( LoadCursor함수 사용 )
    HBRUSH      hbrBackground; -> 윈도우의 배경 색상 지정
    LPCSTR      lpszMenuName; -> 이 프로그램이 사용할 메뉴 지정
    LPCSTR      lpszClassName; -> 윈도우 클래스의 이름을 문자열로 정의
                                   ( CreateWindow함수에 전달됨 )
    /* Win 4.0 */
    HICON       hIconSm;
} WNDCLASSEXA, *PWNDCLASSEXA, NEAR *NPWNDCLASSEXA, FAR *LPWNDCLASSEXA;

 


타이머 관련..

 

SYSTEMTIME구조체
typedef struct _SYSTEMTIME {
    WORD wYear;
    WORD wMonth;
    WORD wDayOfWeek;
    WORD wDay;
    WORD wHour;
    WORD wMinute;
    WORD wSecond;
    WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;

 

 

WM_CREATE 메시지는 WndProc에서 첫번째로 처리하는 메시지.
프로그램 시작시에 꼭 한번만 초기화되어야할 처리를 해준다.

 

case WM_CREATE:
 hTimer = ( HANDLE )SetTimer( hWnd, 1, 1000, NULL );
 return 0;

UINT SetTimer( HWND hWnd, UIN nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc )

hWnd : 타이머 메시지를 받을 윈도우( 보통 WndProc의 인수로 전달되는 hWnd그대로 )
nIDEvent : 타이머의 번호지정( WM_TIMER에서 타이머를 구분하기 위한 표식으로 사용 )
uElapse : 1 / 1000 초 단위로 타이머의 주기를 설정
 ( 1000 이면 1초에 한번 타이머메시지가 hWnd로 보내짐
 Add.. 이 값을 1로 한다고해서 타이머 메시지가 1초에 1000번식 발생하는것은 아님
 타이머의 최대 해상도는 95/98에서는 0.055초, NT/2000에서는 0.01초이기때문에
 주기를 아무리 짧게해도 타이머 메시지는 1초에 100회- 95/98에서는 18회 이상
 발생하지 않는다. )

 


lpTimerFunc : 타이머 메시지가 발생할 때마다 호출될 함수를 지정하는데 사용됨
  ( 사용하지 않을경우 NULL )

 

BOOL KillTimer( HWND hWnd, UINT uIDEvent );

hWnd : 이 타이머를 소유한 윈도우 핸들
uIDEvent : 타이머의 ID

 

 

..
궁금한게 생겼다..
윈도우에서 기본적으로 만들 수 있는 "Hello World!"프로그램소스에서
"Hello World!"라는 문자열은 어디서부터 입력을 받지..?
=> 알았다. 리소스에 문자열로 등록되어있쥐~ IDS_HELLO라는 ID로.

 

 

밖에 외국인 노동자들 체육대회.. 비스무리한거 하더라..
학교올때부터 좀 많이보이네.. 할정도디만.
화장실 갔다오면서 평행봉 찾으러 운동장에 가니깐... 뭐 하데
복닥복닥 하구만..

 

 

강제로 메시지가 발생한것처럼 만들어야 할때..
LRESULT SendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
ex>
SendMessage( hWnd, WM_TIMER, 1, 0 );
( WM_TIMER 메시지는 wParam으로 타이머 ID를 전달받고,
 lParam으로 타이머메시지발생시 호출될 함수의 번지가 전달된다. )

UINT SetTimer( HWND hWnd, UIN nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc )
에서 네번째 인수값 TIMERPROC lpTimerFunc..은 타이머 프로시저 함수의 포인터를 가리킴

VOID CALLBACK TimerProc( HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime );
hWnd : 타이머를 소유한 윈도우 핸들
uMsg : WM_TIMER
idEvent : 타이머 ID
dwTime : Windows가 실행된 후의 경과시간...  잘 사용안되니깐 알필요 별로 없다.

 

 

CallBack함수란..?
응용프로그램에서 제공하며, 운영체제가 필요할때 호출하는 프로그램 내부의 함수.
일반 API함수들은
프로그램에서 필요로 할때, 운영체제가 제공하는 함수들을 호출함.

 

 

BOOL GetClientRect( HWND hWnd, LPRECT lpRect );

static RECT rt; 라 하면, RECT구조체
typedef struct _RECT {
  LONG left;
  LONG top;
  LONG right;
  LONG bottom;
} RECT, *PRECT; 의 left와 top은 0 이 되고, right, bottom엔 우하단의 좌표가 대입됨.


 

WM_SIZE 메시지..
윈도우의 크기가 변경될때 보내지는 메시지.
lParam의 하위 워드에는 변경된 후의 윈도우의 폭. ( rt.right = LOWORD( lParam ) )..
lParam의 상위 워드에는 변경된 후의 윈도우의 높이. ( rt.bottom = HIWORD( lParam ) ).
wParam에는 메시지가 발생한 이유를 나타내는 플래그가 전달..
( SIZE_MAXHIDE, SIZE_MAXIMIZED, ..... )

 

 

WM_MOVE 메시지는
윈도우의 위치가 변경될때 보내지는 메시지
lParam의 하위워드에 윈도우의 새 X좌표
lParam의 상위워드에 윈도우의 새 Y좌표가 전달됨
윈도우가 이동될때마다 특별한 일을해야된다면..사용
-> 잘 사용되지 않음

 


///////// 4장 "입력" 끝.

 

 

 


///////// 5장 "리소스" 시작.

 

리소스..
코드의 논리와 무관한, 프로그램에서 요구하는 데이터들..


*.h + *.cpp => *.obj
*.ico + *.bmp + *.rc => *.res
*.obj + *.res => *.exe -_-

 

WM_COMMAND..
프로그램 실행중에 사용자가 메뉴 항목을 선택하면 WM_COMMAND 메시지가 발생함.
wParam의 하위 워드로 선택된항목을 전달(그 컨트롤의 ID 전달)=> LOWORD( wParam )
wParam의 상위 워드로 컨트롤이 보내주는 통지메시지를보냄
( 메뉴가 선택된경우 0, 액셀러레이터(단축키)가 선택된경우 1 )
lParam에는 통지 메시지를 발생시킨 컨트롤의 윈도우 핸들전달됨.

 

리소스에 등록되어있는 문자열 읽어오는 함수.
LoadString( HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax );
hInstance : 문자열 리소스를 가진 인스턴스 핸들
uID : 읽어올 문자열의 ID
lpBuffer : 문자열을 읽을 버퍼
nBufferMax : 버퍼의 길이
ex>
LoadString( hInst, IDS_STRING110, strBuffer, 256 );

그냥 TextOut( hdc, 10, 10, strBuffer, strlen( strBuffer ) );
해서 출력해도 되는데 왜 리소스로 등록까지해서 사용할까..
1. 문자열이 코드와 분리됨으로써, 문자열만 따로 관리 할 수 있다.
프로그램이 커지면 에러메시지등의 여러 문자열메시지가 만들어질껀데
이게 다 코드에 들어가있으면 양이 엄청 커지게 된다.
2. 다국어 버전을 쉽게 만들 수 있단다..
머.. 수출이나 될까 모르겠지만.


머.. 이렇게 5장 "리소스"는 대충 끝냄..
////////////////////////////////////////

 


////////////////////////////////////////
6장 그래픽. 시작.

 

GDI 란?
모든 출력장치를 제어하는 모듈. Windows프로그램에서의 모든 출력은
GDI를 통해 화면과 프린터 등으로 나가게된다.

 

GDI 오브젝트란 ?
출력에 사용되는 도구.( 펜, 브러시, 비트맵, 폰트 .. )
GDI 오브젝트를 모아놓은것이 DC.
GDI는 현재 DC로 선택된 GDI오브젝트를 사용한다.


사각형 그리는 함수
Rectangle( hdc, 500, 200, 700, 400 ); 썰렁~;

 

GDI 오브젝트를 DC에 선택할때
HGDIOBJ SelectObject( HDC hdc, HGDIOBJ hgdiobj );
리턴값은 새로 선택되는 오브젝트 이전에 선택되어있던 같은 종류의 오브젝트 핸들

 

HBRUSH MyBrush, OldBrush;
....

MyBrush = ( HBRUSH )GetStockObject( GRAY_BRUSH );
OldBrush = ( HBRUSH )SelectObject( hdc, MyBrush );
Rectangle( hdc, 500, 200, 700, 400 );
SelectObject( hdc, OldBrush );
=> 회색 스톡오브젝트 선택후에 사각형을 그렸으니깐,
사각형의 내부는 회색으로 채워짐.


COLORREF..

typedef DWORD   COLORREF; 로 정의되어있다. => 그냥 4바이트 정수일뿐..-_-
상위 8비트는 사용안하고. 다음은 B, 다음은 G, 다음은 R

그래서 그냥 16진수로도 표현이 가능하다..
0 => 검정색 ( xxxx xxxx  0000 0000  0000 0000  0000 0000 )
0xff => 빨간색 ( xxxx xxxx  0000 0000  0000 0000  1111 1111  )
0xff00 => 녹색 ( xxxx xxxx  0000 0000  1111 1111  0000 0000  )
0xff0000 => 파란색 ( xxxx xxxx  1111 1111  0000 0000  0000 0000 )
0xffffff => 흰색.. ?

 

근데, 표현이 기계적이라고 매크로 함수를 만들어놨다네..

#define RGB(r,g,b)     
(( COLORREF )( ( ( BYTE )( r ) | ( ( WORD )( ( BYTE )( g ) ) << 8 ) )|( ( ( DWORD )( BYTE )( b ) ) << 16 ) ) )

머가 더 기계적인지 모르겠다. -_-; ...

 

RGB( 255, 0, 0 ) 은 빨간색
RGB( 0, 0, 255 ) 은 파란색
RGB( 0, 255, 0 ) 은 녹색
RGB( 0, 0, 0 ) 은 검정색
RGB( 255, 255, 255 ) 은 흰색

 

 

색상요소의 농도를 분리해내는 함수..
#define GetRValue(rgb)      ((BYTE)(rgb))
#define GetGValue(rgb)      ((BYTE)(((WORD)(rgb)) >> 8))
#define GetBValue(rgb)      ((BYTE)((rgb)>>16))

 

col이라는 색상형 변수가 있을때 GetBValue( col )하면 그 색상중 파란색만 추출.

 

 

펜".. 은 선을 그을때 사용되는 GDI오브젝트다.

기본제공되는 스톡펜은 흰색, 검정색, 투명색 세가지 뿐.

다른색깔은
HPEN CreatPen( int fnPenStyle, int nWidth, COLORREF crColor );
으로 만들어써야된다. 인수는 보면 알겠네. ㅎ

 

리턴값으로는 만들어진 펜의 핸들을 돌려줌. 이값을 보관해두어야
만들어진 펜을 사용할 수 있다.

 

 

GDI오브젝트는 사용한 후 반드시 삭제해주어야함. GDI 오브젝트도 메모리기때문에.

BOOL DeleteObject( HGDIOBJ hObject );

 

 

HPEN MyPen, OldPen;
MyPen = CreatePen( PS_SOLID, 5, RGB( 0, 0, 255 ) );
OldPen = ( HPEN )SelectObject( hdc, MyPen );
Rectangle( hdc, 400, 100, 500, 200 );
SelectObject( hdc, OldPen );
DeleteObject( MyPen );

 

 

HBRUSH MyBrush, OldBrush;
MyBrush = ( HBRUSH )GetStockObject( GRAY_BRUSH );
OldBrush = ( HBRUSH )SelectObject( hdc, MyBrush );
Rectangle( hdc, 500, 200, 700, 400 );
SelectObject( hdc, OldBrush );

 

 

HGDIOBJ SelectObject( HDC hdc, HGDIOBJ hgdiobj );
GDI 오브젝트를 DC에 선택하고..
리턴값은 새로 선택되는 오브젝트의 이전에 원래 선택되어있던
같은 종류의 오브젝트 핸들값이었다.

 

SelectObject( hdc, OldPen );
DeleteObject( MyPen ); 이 두줄은
DeleteObject( selectObject( hdc, oldPen ) ); 라고도 사용가능하다..

=> GDI 오브젝트를 만들어 사용할때는 항상 같은타입의 Old 핸들을 하나 더 선언해야한다.
( DC에 현재 선택되어있는 GDI오브젝트는 삭제할수 없다. so, MyPen... 을 삭제하기위한 용도 )


(모든)GDI오브젝트를 만들고 사용하는 일반적인 절차.

1. 핸들을 선언한다   =>  HPEN MyPen, OldPen;
2. GDI 오브젝트 만듬 =>  MyPen = CreatePen(... );
3. DC에 선택하되 이때 이전핸들을 반드시 저장해두어야 한다.
    OldPen = SelectObject( hdc, MyPen );
4. 사용한다          =>  Rectangle( ... ).. ;
5. 선택을 해제한다   =>  SelectObject( hdc, OldPen );
6. 삭제한다          =>  DeleteObject( MyPen );


 

브러시를 만드는 함수

 

HBRUSH CreateSolidBrush( COLORREF crColor );

단색의 브러시


HBRUSH CreateHatchBrush( int fnStyle, COLORREF clrref );

색상, 무늬 지정
두 함수 모두 만들어진 브러시의 핸들값을 리턴함.

 


그리기모드

흑백에서 그리기모드


COPY : 새로그려지는 그림이 기존 그림을 덮어버림
OR : 두 그림의 대응되는 비트를 OR연산하여 새로 값을 써 넣는다
AND : 두 그림의 교집합 영역만 그려짐
XOR : 두 그림중 겹쳐지는 부분이 반전됨.

 

그리기모드 변경
int SetROP2( HDC hdc, int fnDrawMode );
현재 설정된 그리기 모드를 구함
int GetRop2( HDC hdc ); => DC에 설정되어있는 현재 그리기 모드값을 리턴

 

 


 

'- 음악과 나 - > 『 짬 통 』' 카테고리의 다른 글

소스세이프..가이드.  (0) 2006.04.17
about. PM  (0) 2006.04.16
4월 14일. - 뿔랙데이  (0) 2006.04.14
SSDN  (0) 2006.04.14
[스크랩] 오랜만이다. 아스키코드ㅋㅋ  (0) 2006.04.09