달력

62025  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

'MFC'에 해당되는 글 4건

  1. 2014.03.17 비트맵과 이미지 처리
  2. 2014.03.17 키보드 입력
  3. 2014.03.17 MFC코드의 기본 구조
  4. 2014.03.17 WinMain함수

비트맵과 이미지 처리

MFC 2014. 3. 17. 02:38

■전형적인 이미지 출력
 - 윈도우 프로그래밍에서 비트맵 이미지를 출력하는 전형적인 방법은 리소스로 등록된 비트맵 이미지를 메모리 DC에 로드 하여
    화면 DC로 출력(BitBlt())하는것입니다. 이과정을 요약하면, 이미지의 크기를 변경(StretchBlt())하거나 일부영역을 투명하게
   처리(TransparentBlt())하거나 반투명하게 처리(AlphaBlend())하게 됩니다.

   비트맵은 장치의존적인 비트맵(DDB, Device Dependent Bitmap)과 장치 독립적인 비트맵 (DIB, Device Indepent Bitmap)으로 
   나누어집니다. 장치 의존적이냐 장치 독립적이냐는 말은 장치의 영향을 받느냐 그렇지 않느냐의 의미로 해석 됩니다.
   우리가 아는 비트맵파일은 모두 DIB라고 봐도 무방합니다. 비트맵을 우리눈으로 보려면 DDB로 변환해야합니다.



 비트맵을 저장할 메모리 DC를 생성하되 출력할 화면 DC와 호환이 되도록합니다. 그리고 비트맵을 로드하고 메모리 DC의
 비트맵으로 선택합니다. 최종적으로 BitBlt()함수를 호출하여 메모리 DC에 로드된 비트맵 이미지를 화면 DC로 전송합니다.
 화면 DC로 비트맵을 전송하면 내부적으로 DIB가 DDB로 변환되어 모니터 화면에 출력하게됩니다.


CDC클래스의 CreateCompatibleDC() 메서드는 CDC클래스 객체의 주소를 인자로 받으며 전달받은 CDC클래스 객체와 호환되는 
메모리 DC를 생성합니다. 메모리 DC는 출력할 비트맵 이미지를 저장하는 메모리 공간이라 할수있습니다.

CDC클래스의 BitBlt() 함수는 메모리 DC에서 화면 DC로 비트맵을 전송해 줍니다.
BitBlt()원형

BitBlt()함수는 메모리 DC에서 이미지의 일부 혹은 전체를 뗴어서 화면 DC로 전송합니다.

함수의 x,y인자는 화면 DC에서 출력을 시작하는 좌표.
nWidth,nHeight 인자가 각각 250,300 이되었는데, 화면DC에서 출력할 이미지의 크기를 말합니다.
xSrc,ySrc 인자는 출력할 원본이미지를 시작하는 좌표입니다.
원본이미지의 폭과 높이는 명시하지않았지만, 출력할 이미지와 같은 크기로 잘라냅니다.

BitBlt()함수의 마지막 인자에는 래스터 연산을 어떻게 할지 명시하는데,SRCCOPY는 메모리 DC의 내용에 변화를 주지 말고 그대로
화면DC에 복사 하라는 의미. 

dwRop연산

 BLACKNESS검정색으로 채운다 
 WHITENESS흰색으로 채운다 
 DSTINVERT화면을 반전 
 MERGECOPY소스 비트맵과 바탕화면을 AND연산한다.
 MERGEPAINT소스 비트맵과 바탕화면을 OR연산한다. 
 SRCCOPY소스영역을 대상 영역에 복사한다. 
 SRCAND타겟과 AND연산. 
 SRCINVERT타겟과 XOR연산
 SRCPAINT 타겟과 OR연산
 SRCERASE타겟과 NOT소스를 AND 
※레스터 연산에서 래스터란 화면을 이루는 수평선을 의미.
가령 폭과 높이가 300*200인 비트맵 이미지가 있다면 200개의 수평선이 있는 이미지를 의미. 래스터 연산을 한다는것은
이미 화면에 출력된 래스터와 출력할 래스터를 어떻게 조합할것인지를 연산하는것입니다. 즉, 각각의 픽셀 하나하나에
대해 AND,OR,XOR과 같은 비트 연산을 하는 것입니다. 따라서 이값을 어떻게 조합하느냐에 따라 화면 이미지를 덮어쓰게
되기도 하고 일정 부분 섞여서 출력하기도 합니다.


StrechBlt()함수는 BitBlt()함수처럼 메모리 DC에 로드된 비트맵 이미지를 화면 DC에 출력하는 기능을 한다는 점에서는 같지만
원본 크기와 대상 크기를 달리하여 이미지를 확대 축소 출력한다는 점이 다름.


■고급 이미지 출력 함수
TransparentBlt()와 AlphaBlend() 두함수는 모두 예전에는 CDC클래스의 맴버가 아니였으나, MFC를 업그레이드 하면서 맴버로
추가되었습니다. 

 TransparentBlt()함수와 StretchBlt()함수 인자가 거의 비슷합니다.
StretchBlt()함수의 마지막 인자는 래스터 연산값이지만, TransparentBlt() 함수의 마지막 인자는 투명하게 출력할 RGB값입니다.
위의 소스에서 RGB값이(0,0,0)이므로 검정색이 됩니다. 따라서 메모리 DC에 로드된 비트맵의 색상중에 검정색은 투명하게 출력
될것입니다.


AlphaBelnd()함수는 전체이미지를 반투명하게 만듭니다.
AlphaBlend()함수의 마지막 인자 BLENDFUNCTION구조체는

BlendOp 맴버에는 원본이미지와 대상이미지를 섞는 연산을 명시합니다.
AC_SRC_OVER은 원본/대상 이미지를 서로 섞는다는 의미.
BlendFlags 맴버는 사용하지않으면 반드시 0이어야함.
SourceConstantAlpha 맴버는 원본이미지의 투명도를 결정하며 0~255범위값을 같습니다.
0이면 완전 투명(아무출력하지않음.) 255면 완전히 불투명해집니다.
BLENDFUNCTION 구조체의 마지막 맴버인 AlphaFormat에는 원본과 대상 비트맵 이미지를 해석하는 방법을 명시합니다.
이값은 0이나 AC_SRC_ALPHA가 되어야합니다.
AC_SRC_ALPHA가 되는 경우 원본 비트맵이 24비트 이하의 비트맵이 아니라 각 픽셀에 대한 알파 채널을 갖는 진정한 32비트
비트맵인경우에만 해당합니다.

■CImage 클래스의 활용

CImage 클래스는 MFC가 제공하는 ATL 클래중하나입니다. 그러므로 내부적으로는 COM객체로 구현되어 있습니다.
C++의 클래스가 논리적인 코드를 객체화한 개념이라면 COM은 실행 바이너리 파일 단위로 객체화한 것이라고 할수있다.
그러므로 메서드가 반환하는 값은HRESULT형이며, FAILED()매크로나 SUCCEEDED()매크로를 이용해 오류를 확인합니다.
CImage클래스의 Load() 메서드는 인자로 전달받은 경로의 이미지 파일을 로드하여 DIB이미지를 생성합니다.
유사 함수로 LoadFromResource()메서드가 있습니다. 이 함수는 CBitmap 클래스의 LoadBitmap() 메서드처럼 비트맵 리소스를
로드하여 비트맵 이미지를 만듭니다.사용하는 인자도 리소스 ID를 주어야한다는 점에서 같지만 첫번째 인자로 ::LoadImage() API
함수처럼 응용프로그램의 인스턴스 핸들을 주어야합니다.


메모리DC를 이용한 전형적인 이미지 출력보다 훨씬 코드가 간단해집니다.
CImage 클래스에는 GetDC()와 ReleaseDC()메서드가 있습니다.이들메서드는 CDC클래스의 GetDC()와 ReleaseDC()함수와 유사
합니다.다만, 생성한 비트맵 객체가 이미 있다는점에서 차이가 납니다.


구현방법은 화면 DC에 이미지를 출력한 다음에 추가로 문자열을 화면 DC에 출력하는 방법과 이미지DC에 문자열을 출력하고
변경한 이미지를 화면 DC에 출력하는 방법이있습니다. 별다를것없이 보이지만 화면의 깜빡임을 제거하는 코드를 만들려면
두방법은 극단적인 차이를 보입니다.

GetDC()메서드를 이용하면 DC의 핸들인 HDC데이터를 반환합니다. MFC의 CDC클래스는 내부적으로 m_hDC라는 핸들 맴버를
갖고있습니다. 이것은 CWnd클래스가 윈도우 핸들맴버로 갖는것과 비슷합니다. 그리고 CDC 클래스의 정적 맴버인 FromHandle()
함수를 명시적으로 호출하여 HDC에 대한 CDC클래스 객체의 포인터를 반환받습니다.

CDC클래스 객체는 CImage클래스 객체와 연결된 메모리DC가 되는데, 이것을 앞서배운 메모리DC와 구별하기위해 이미지DC라고
부릅니다. 이미지DC는 CImage 클래스 객체와 연결되어있으므로 나중에 CImage::ReleaseDC()메서드를 호출하여 리소스반환.

문자열의 배경을 투명하게 하고 TextOut() 함수를 이용하여 이미지 DC에 문자열을 출력하는 코드입니다.

함수의 원형| Bitblt()


■색상의 변환
윈도우 프로그래밍에서는 이미지를 처리할때 RGB방식을 사용합니다. 하지만, HSB/HSV색상, Saturation 명도, Brightness 밝기,
Value깊이 방식을 사용하여 색상을 표현하기도 합니다.
RGB컬러를 흑백으로 변환하는 방법은 매우간단하며 공식처럼 활용됩니다.

GetRValue(), GetGValue(), GetBValue() 함수는 COLORREF값에서 RGB값을 각각 추출하는 매크로입니다.
24비트 컬러에서 각각은 8비트이며, RGB각각에 대해 30,59,11을 곱한 값을 모두더해 다시 100으로 나누면 흑백에 해당하는
값을 구할수 있습니다.
CWnd 클래스의 GetDesktopWindow() 메서드는 바탕화면 윈도우 객체의 포인터를 반환합니다.
이렇게 해서 알아낸 바탕화면에 대한 DC를

로 생성합니다. 이때 CPaintDC클래스나 CClientDC클래스를 사용하지않고 CWindowDC클래스를 사용한것은.
CWindowDC클래스는 다른 형제 DC들과 달리 비클라이언트 영역을 포함한 윈도우 전체에 대한 DC입니다.

비트맵 파일이나 리소스를 로드하는것이 아니라 폭과 높이가 각각 300픽셀이고 바탕 화면 윈도우 DC의 픽셀당 비트수가 같은 비트맵 
이미지를 생성합니다. CDC클래스의 GetDeviceCaps()메서드는 DC의 각종 정보를 추출합니다.인자로 전달받은 인덱스에따라
각각 다른 값을 int형 값으로 반환합니다. 

일부이미지(200*200)을 흑백으로 변환(RGBtoGray)합니다. 이과정에서 CImage클래스의 GetPixel()과 SetPixel() 함수를
사용하였는데, 비트맵 이미지를 2차원 배열이라고 가정하고 원하는 특정 지점의 좌표를 이용하여 RGB값을 가져오거나 실행합니다.
같은 이름의 함수가 CDC클래스에도 있으며 기능도 같습니다. 이렇게 일부 영역의 이미지를 흑백이미지로 변환하여
화면에 출력하고 모든 처리를 종료합니다.

CImage클래스의 Create()메서드의 원형

마지막 인바의 기본값은 0입니다. 이인자에는 32비트 비트맵일경우 알파 채널을 명시합니다. 세번째인자(nBPP)가 반드시 32가 되어야 알파 채널을 명시할수 있습니다. 
CDC클래스의 GetDeviceCaps()메서드는 인자로 전달받은 인덱스에 해당하는 DC정보를 반환해줍니다.

윈도우 탐색기는 윈도우 운영체제의 셀입니다. ::ShellExecute() API함수의 원형은 다음과 같습니다.
함수의원형 | ShellExecute()

hwnd 인자는 부모 윈도우의 핸들이며, 이값이 NULL이면 부모윈도우는 바탕화면이 됩니다.
lpOperation 인자에는 함수가 어떤 동작을 할것인지 명시합니다.
lpFile인자와 연결된 프로세스를 실행하라는 의미.
lpFarameters 인자에는 lpFile인자가 싱행 파일인 경우 실행할 파일의 실행인자를 명시합니다.
lpDirectory 인자에는 실행할 프로그램의 현재 폴더 경로를 명시합니다. 이값이 NULL이면 윈도우 기본 설정을 적용 합니다.

'MFC' 카테고리의 다른 글

키보드 입력  (0) 2014.03.17
MFC코드의 기본 구조  (0) 2014.03.17
WinMain함수  (0) 2014.03.17
Posted by 레이드리안
|

키보드 입력

MFC 2014. 3. 17. 02:37

 

키보드 관련 대표적인 메세지는 WM_KEYDOWN WM_KEYUP

 

특정키를 계속 누르고 있으면 WM_KEYDOWN 메세지가 계속 발생함.

 

메세지를 전달할떄는 어떤키를 눌렀는지에 대한 파라미터가 담겨있음.

 

키보드 메세지는 모든키에 발생하지만 예외가 있음.

 

예외) Alt     F10

 

두키를 누르면 WM_KEYDOWN 메세지가 발생하지 않고 WM_SYSKEYDOWN 메세지가 발생함그리고 이메세지와 WM_SYSKEYUP 메세지가 짝을이룸.

 

WM_KEYDOWN 메시지의 파라미터에 ASCII코드의 문자에 해당하는 키가 입력될경우

 

메세지 루프의 TranslateMessage()함수가 WM_KEYDOWN 메시지를 다시 WM_CHAR 메시지로 전환하여 전송함.

 

 

<소스 코드 5-03>==================================

 

void CKeyMoveView::OnKeyDown(UNIT nChar, UINT nRepCnt, UINT nFlags)

{

  CPoint ptChild; //차일드 윈도우의 좌표.

  CPoint Rect;    //차일드 윈도우의 좌표및 크기.

 

  m_wndChild.GetWindowRect(&Rect);//차일드 윈도우의 두 좌표 정보(스크린 기준)를 가져온다.

 

  ptChild.x = Rect.left;

  ptChild.y = Rect.top

 

  ScreenToClient(&ptChild); // 스크린 기준 좌표를 클라이언트 뷰 기준의 좌표로 변환.

 

  switch(nChar)

  {

    case VK_LEFT:   //방향키 왼쪽이 눌러지면..

          ptChild.x -=10;// 10픽셀만큼 x좌표 값 에서 감소.

        break;

    case VK_RIGHT:  // 방향키 오른쪽이 눌러지면

        ptChild.x +=10;// 10픽셀만큼 x좌표 값 에서 증가.

        break;

  }

  

  m_wndChild.SetWindowPos(&CWnd::wndTop,ptChild.x,ptChild.y,0,0,

            SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOSIZE);

 

  CView::OnKeyDown(nChar,nRepCnt,nFlags);

 

}

 

======================================================

 

윈도우 좌표계와 활용함수(GetWindowRect(),SetWindowsPos())를 이해하고,

CPoint CRect 같은 데이터 클래스에 대해서도 알아야한다.

 

 

 

 

<소스코드 5-04>======================================

/*

 * Virtual Keys, Standard Set

 */

 

 #define VK_LBUTTON 0X01

 #define VK_RBUTTON 0X02

 #define VK_CANCLE 0X03

 #define VK_MBUTTON 0X04

 

 #if(_WIN32_WINNT >= 0X0500)

 #define VK_XBUTTON1 0X05

 #define VK_XBUTTON2 0X06

 #endif /* _WIN32_WINNT >= 0X0500 */

=====================================================

 

OnKeyDown() 메시지 핸들러 함수의 첫번째 인자인

nChar에는 어떤키를 눌렀는지에 대한 정보가 들어있다.

이런값을 가상 키값(Virtual Key Code)이라 하며, WinUser.h파일에 정의되어있다.

ESC 키의 경우 VK_ESCAPE이며, ENTER 경우 VK_RETURN.

윈도우에서는 알파벳이나 숫자처럼 사람이 인식하는 문자열과 관련된 키에 의한 발생한 WM_KEYDOWN메시지는 WM_CHAR 메시지로 전환하여 재전송하게됨.

이런 작업은 메시지 루프에서 TranslateMessage() 함수가 처리.

그러므로 문자열 입력을 처리하고 싶다면 WM_CHAR메시지 핸들러를 등록하는 것이 바람직함.

nRepCnt인자는 반복횟수를 의미.(대부분의 횟수는 1)// 키를 계속누르고 있으면, 2 3이 될수도있고 그이상이 될수도음.

nFlags 인자는 키보드에 대한 상세한 상태 정보를 담고있음.(비트 단위로 잘라서 특정 범위값을 살펴 봐야함.)

VK_RIGHT 는 오른쪽 화살표를 눌렀을때도 해당하지만 키패드에서 Number Lock 을 끈상태에서는 숫자 6을 눌렀을때에도해당함만일 둘을 구별해야한다면 nFlags에서 특정 비트의 값을 확인하여 판별가능.

스캔코드의 값은 모두 같아 보이지만 확장키의 비트값이 차이가있음그리고 방향키를 누르더라도 여러키(Ctrl + Alt)를 조합하면 차이가 생김.

<그림 5-1>참조 !!!!!.

0~7  : 스캔코드(키보드의 특정키를 식별하는 값.)

8      : 확장키(1이면 확장키)

9~10 : 사용하지않음.

11~12: 윈도우 OS에서 사용

13    : 비트컨텍스트(1이면 Alt키가 눌러진상태)

14    : nChar값에해당키 (0이면 키가 눌린상태)  WM_KEYDOWN 메시지는 키를 눌렀을때 발생하기 때문에.

15    : 비트 전송 코드 (0이면 키를 누른상태  WM_KEYDOWN 메시지의 특성상 이값이 0)

 

nFlag 값의 변화를 확인하고 싶다면 OnKeyDonw() 메시지 핸들러 함수에 중단점을 설정(F9) 디버그 모드로 실행(F5)

 

CPoint CRect 같은 클래스들은  각각 POINT  RECT 구조체를 클래스화 하고 연산자를 정의한것.

CPoint 클래스의 가장중요한 맴버함수는 x,y

CRect 클래스의  중요맴버함수는 left, right, top, bottom

그리고 가장 많이 사용하는 메소드로는 Width()  Height() 등이있음.

GetWindowRect() 함수는 CWnd클래스의 맴버이며모니터기준 왼쪽 위와 오른쪽아래의 좌표를 알아내는 함수.

Rect구조체에 m_wndChild 윈도우를 모니터 기준 좌표로 반환.

왼쪽위좌표를 CPoint 클래스에 저장이좌표를 변환하여 현재위치를 파악하고 눌러진 키보드가 무엇인지 확인하여 새로운 위치로 윈도우를 이동시킴.

ScreenToClient() 함수는 CWnd 클래스의 맴버함수이며, POINT 구조체로 전달받은 좌표를 특정윈도우 기준 좌표로 변환.

<그림 5-3> 기준으로 GetWindowRect() 함수로 얻은 왼쪽위의 좌표(C) (300,250)이 되고, ScreenToClient()함수를 호출

하여 클라이언트 뷰 기준으로 변환 하면 (100,100) 이됨.

SetWindowPos()함수는 윈도우의 위치크기,Z-order를 변경하는 함수원형은

===========<SetWindowPos()>================

BOOL SetWindowsPos(

  const CWnd *pWndInsertAfter,

  int x, int y,

  int cx, int cy,

  UINT nFlags

);

=======================================

pWndInsertAfter 인자는 함수를 호출한후 윈도우의 Z-order 를 어떻게 할것인지 명시.

Z-order란 두윈도우가 겹쳤을때 어떤것이 아래이고 어떤것이 위인지 결정하는값.

SWP_NOZORDER로 주면 NULL앞과같이 이런 플래그를 설정하지 않았다면 값은 NULL이 될수 없으며 CWnd 클래스의 스태틱 맴버중에 하나의 값으로 설정되어야한다,]

=========== CWnd클래스 스태틱 맴버 ===========

static AFX_DATA const CWnd wndTop;

static AFX_DATA const CWnd wndBottoml;

static AFX_DATA const CWnd wndTopMost;

static AFX_DATA const CWnd wndNoTopMost;

 

BOOL SetWindowPos(const CWnd * pWndInsertAfter, int x, int y,

                 int cx, int cy, UINT nFlags);

 

(SetWindowPos()  Z-order)

=================================================

Z-order             |                

-----------------------------------------------------------------------------------------

WndBottom        | Z-order를 최하위로 합니다.

------------------------------------------------------------------------------------------

WndTop            |Z-order를 최상위로 합니다.

-------------------------------------------------------------------------------------------

WndTopMost      |Z-order를 최상위로 하고 시스템 윈도우 속성을 갖습니다.

--------------------------------------------------------------------------------------------

WndNoTopMost  | 일반윈도우 중 최상위 윈도우가 되도록합니다.

==================================================== 

=========================================================

x,y 인자는 새로 설정할 윈도우의 왼쪽 위 좌표.

예제에서는 이값을 변경하여 윈도우의 위치를 변경만일 SWP_NOMOVE 플래그로 설정하면 두인자는 무시.

cx, cy인자는 새로설정할 윈도우의 폭과 높이예제에서는 SWP_NOSIZE로 설정되어있어 값은 0(윈도우크기변경X)

 

 ======================nFlags===============

SWP_HIDEWINDOW    |  윈도우가 화면에서 사라지도록 함.

-------------------------------------------------------------------------

SWP_SHOWWINDOW | 윈도우가 화면에 보이도록 함.

------------------------------------------------------------------------

SWP_NOACTIVATE    | 윈도우를 활성하지 않음.

-----------------------------------------------------------

SWP_NOMOVE        | 윈도우의 위치를 변경하지않음(x,y값무시)

----------------------------------------------------------

SWP_NOREDRAW   | 윈도우를 다시그리지 않음.

-----------------------------------------------------------

SWP_NOSIZE        | 윈도우의 크기를 변경하지않음.(cx, cy값 무시)

-----------------------------------------------------------

SWP_NOZORDER   | 윈도우의 Z-order 를 변경하지 않습니다 (pWndInsertAfter 무시)

==============================================

 

-WM_KEYDOWN 메세지에서 모든것을 처리한다면 OnKeyDown()함수가 길이가 너무 커질수 있으므로, WM_CHAR메세지 핸들러를 추가 하여 특수키입력과 문자키 입력을 구분하여 처리할것!

=========<소스코드 5-08>====================================

void CKeyMoveView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

{

  CString strText = TEXT(" "); // 문자열을 선언하고 빈문자열로 초기화

  strText.Format(TEXT("%c"),nChar);

  //입력한 키가 Enter, Back, ESC키가 아니면

  //해당 ASCII문자로 차일드 윈도우 텍스트를 변경한다.

  if(nChar != VK_RETURN && nChar != VK_BACK && nChar !=VK_ESCAPE)

   {

     m_wndChild.SetWindowText(strText);

   }

   CView::onChar(nChar, nRepCnt,nFlags);

}

===============================================================

nChar인자값이 Enter,BackSpace,ESC 키인지 검사를 하면 WM_CHAR메세지가 발생.

 예제에서는 문자를 출력하려고 시도하지만당연히 제대로 된 ASCII코드가될수없음.

 그래서 세가지 키입력에 대해서는 예외처리.

OnChar() 함수의 nChar(어떤키가 눌렀는지 nRepCnt(몇회눌러졌는지인자는 OnKeyDown()함수와 같지만

nFlags인자는 다름 32bit를 사용하고 있으며의미가 있는 비트의 위치가 다름.

CString코드의 장점

ⓐ유니코드 문자열을 처리하고 일반 멀티 바이트 문자열을 처리하는 코드나 함수를 따로 분리하지 않아 처리가 훨씬

   간단함.

ⓑ더하기 연산자나 할당연산자가 정의 되어있음.

ⓒ문자열 처리에 필요한 메모리를 알아서 관리 하기떄문에 메모리를 할당/해제 하는 코드를 작성할 필요가 없음.

 

SetWindowText() 함수는 CWnd 클래스의 맴버함수.

인자로 전달받은 문자열로 윈도우의 텍스트를 변경이와 쌍을 이루는 함수로 GetWindowText()함수도 있음.

 

윈도우 운영체제에서는 Alt 키나 F10 키를 누르면 메인 메뉴포커스로 이동.

이 두키에 대한 입력이 발생하면 WM_KEYDOWN WM_KEYUP 메시지가 아니라 WM_SYSTEMDOWN WM_SYSKEYUP

메시지가 발생함.

============<소스코드 5-09>=============================

void CKeyMoveView::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)

{

   CString strMessage =TEXT("");//메시지를 저장할 문자열 객체.

   //Space 키에 대한 상태 정보를 수집

  WORD wResult = ::GetKeyState(VK_SPACE);

  BYTE byHigh = HIBYTE(wResult);

  //상위 바이트 의 1번 비트가 1이면 키가 눌러진 상태

  if(byHigh & 0x01)

  {

    strMessage += TEXT("Alt+Space,");

    //같은 방법으로 Caps Locks 키 상태를 검사

  wResult = ::GetKeyState(VK_CAPITAL);   //  :: API에서 함수를 찾음.

   //하위 바이트의 1번 비트가 1이면 토글 키가 켜진상태

   BYTE byLow =LOBYTE(wResult);

   if(byLow & 0x01)strMessage += TEXT("CAPS LOCK ON");

   else strMessage += TEXT("CAPS LOCK OFF");

   AfxMessageBox(strMessage);

  }

 CView ::OnSysKeyDown(nChar, nRepCnt, nFlags);

}

=========================================================

OnSysKeyDown() 함수의 인자는 OnKeyDown() 함수와 같습니다.

OnSysKeyDown()함수는 Alt키와 조합된 키입력에 대한 호출지금의 코드에서는 ::GetKeyState() API 함수를 이용하여

특정키의 상태를 검사하고 Alt키와 조합됬는지 확인.

==========================GetKeyState()함수의원형==============

SHORT GetKeyState(

   int nVirtKey // vitual -key code

);

=========================================================

 

인자로는 상태를 검사할 키의 가상키값을 받습니다.

WORD wResult = ::GetKeyState(VK_SPACE);  VK_SPACE의 상태를 확인하여 wResult라는 16비트 맴버변수에 결과를 저장하고 있음.

SHORT형이나 WORD형이나 모두 16비트의 크기를 갖음그리고 저장된 값이 얼마인지 단순히 확인하는것이아니라,

다시 상위바이트(8비트)와 하위 바이트로쪼개서 키의 상태를 확인함.

 

HIBYTE()LOBYTE() 매크로는 인자로 주어진 16비트 값에서 각각 상위하위 바이트로 잘라내는 매크로.

GetKeyState()함수가 반환하는 값의 상위 바이트는 키를 누른상태인지에 대한 정보가 들어있고,

하위 바이트에는 토글에 대한 정보가 들어있음.

VK_SPACE는 토글키가 아니므로 굳이 하위정보를 확인할필요없음.

키를 눌렀는지 검사하려고 값을 비교하는 것이 아니라 1번 비트가 1인지 비트 연산(&)하여 확인 합니다.

CapsLocks, NumberLock, ScrollLock 키는 대표적인 토글키.

한번씩 누를때마다 상태가 On/Off되는 특성이있음이런정보는 GetKeyState()함수가 반환한 결과의 하위바이트에 들어있습니다.

On/Off상태는 앞서와같이 1번비트를 확인 하면됨.

CString 클래스의 '+='연산자를 이용하여 문자열을 합침.(C언어에서의 strcat()함수와 동일결과)

WM_SYSCHAR메시지는 TranslateMessage()함수가 생성. WM_CHAR 메시지는 문자키 입력일떄 발생하지만 WM_SYSCHAR메시지는 Alt키와 문자키 입력이 조합된경우에만 발생(ex. Alt+S)

 

 


'MFC' 카테고리의 다른 글

비트맵과 이미지 처리  (0) 2014.03.17
MFC코드의 기본 구조  (0) 2014.03.17
WinMain함수  (0) 2014.03.17
Posted by 레이드리안
|

MFC코드의 기본 구조

MFC 2014. 3. 17. 02:36



응용프로그램도 포함되어있음. -> App + 문서 (Doc)

CWinApp 클래스
 
m_hInstance ▶현재 응용 프로그램의 인스턴스 핸들입니다. WinMain()함수의 첫번째 파라미터인 hInstance와 같은것임.
m_lpCmdLine ▶WinMain() 함수의 lpCmdLine 파라미터와 같은것입니다. 프로그램을 실행하였을때 명령줄 정보가 들어있음.
m_nCmdShow  ▶WinMain()함수의 마지막 파라미터인 nCmdShow와 같은것.
m_pActiveWnd ▶응용프로그램의 최상위 프레임 윈도우에 대한 포인터. SDI구조에서 이값은 CMainFrame 클래스 객체의 포인터.
m_pszAppName ▶응용프로그램의 제목에 해당하는 문자열 포인터. 문자열의 좀더 정확한 정보는 문자열 테이블에 있는 AFX_IDS_APP_TITLE에 해당하는값
m_pszExeName ▶빌드한 실행 파일에서 확장자(.exe)를 제외한 파일명.

가상함수로 정의된 함수중 중요한것!
(InitInstance(), ExitInstance(),Run())

InitInstance()▶메서드는 응용프로그램이 초기화 되는 시점에서 호출되며 Run()메소드와 달리 대부분 재정의 되어있으며, 직접 코드를 수정할수 있다.
 ↓
Run()▶메시지 루프가 시작되는 시점에 CWinApp클래스의 Run()메소드가 호출되는 시점. Run()메서드가 반환하면 응용프로그램은 종료됨.
 ↓
ExitInstance()▶InitInstance()메소드와 반대로 응용프로그램을 종료하는 시점에 호출. 메인메시지 루프를 종료하는 시점(Run()함수가 반환한 시점) 에 호출. 기본적으로 재정의되어있지않지만
                필요한경우 재정의해서 사용가능.


CframeWnd클래스 계층구도

CObject 
    └→CCmdTarget
              └→CWnd
                   └→CFrameWnd

 
CFreameWnd& Control bar windows
  1-2캡쳐


CDocument클래스 계층구도

Cobject
   └→ CCmdTarget
              └→ CDocument

메모장 처럼 한프로그램당 한개의 화면이므로, SDI(싱글도큐먼트)


OnNewDocument() ▶처음시작 할때 불림.(파일을 새로열때.)
AfxMessageBox() ▶Afx - MFC에서 제공하는 전역변수(팝업용 텍스트)
OnOpenDocument()▶문서열기 를 할시에 콜됨.
SetModifiedFlag(True)▶ 무조건 수정된걸로 인식되어 종료시에 저장을 물음.

MessageMap
-------------------------------------------------
BEGIN_MESSAGE MAP(CHelloSdiViewmCEditView) 
  ~~
  ~~
  ~~
END_MESSAGE_MAP()
=================================================

속성으로 WM_CREATE()를 추가하면, 코드도 추가 됨과 동시에 MESSAGE_MAP에도 추가한 코드의 구조체가 추가된다.
WM_CREATE()추가시
-----------------------------------------
BEGIN_MESSAGE MAP(CHelloSdiViewmCEditView)
  ~~
  ~~
  ~~
  ON_WM_CREATE()
END_MESSAGE_MAP()
------------------------------------------


MESSAGE_MAP 은 API의 case문을 대체 함.

'MFC' 카테고리의 다른 글

비트맵과 이미지 처리  (0) 2014.03.17
키보드 입력  (0) 2014.03.17
WinMain함수  (0) 2014.03.17
Posted by 레이드리안
|

WinMain함수

MFC 2014. 3. 17. 02:35


* WinMain 함수
- C언어의 메인과 마찬가지임.. 
  시작되는 함수는 여기에서 처리함


핵심함수: _tWinMain
          MyRegister(hInstance);
          InitInstance


        ★main message loop(가장중요)//메시지 루프
          while(GetMessage(&msg,NULL,0,0))
         {
  if(!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
  {
   TranslateMessage(&msg);
                        DispatchMessage(&msg);
  }
         }

Get Message <-  Msg Queue 에서 가지고옴
메시지를 가져오면 루프를 돌고 메시지를 가지고 오지못하면(quit) 종료되는구조.

윈도우에서 Message란?
-모든것이 다 Message다.(보여지는것,생성되는것,이동되는것,입력 등등...) 
-Message Driven 방식

H.I.D(Human Input Device)- Keyboard, Mouse등(H/W Event 발생)▶OS에서 감지


-키보드에서 키가 눌리면 하드웨어 이벤트가 발생하고, 이이벤트는 OS에서 감지하며 모니터(출력)에 Message로 보내줌.


-DispatchMessage 함수가 호출이 된다면 윈도우 프로시저 함수를 호출(Window Proc)<_Winproc->윈도우창의 인풋에 대해 메시지를 처리함.

메시지 내용은 (HWND hWnd,UNIT message, WPARAM wParam, LPARAM lParam)에 메시지정보를 담고있음.

작업관리자에서 "응답없음"이뜨는것은 메인메시지 에서 루프가 멈추면 "응답없음"발생


Handle 이란 -어떤 포인터에 관한 값.
-------------------------------tWinMain--------------------------

_tWinMain(HINSTANCE hInstance,) ▶응용프로그램 자체를 식별하는 값(실행파일의 메모리상의 위치)

lpCmdLine ▶ 프로그램시작할때 ~~~.exe /?라던지 실행할때쓰는것
nCmdShow ▶ 윈도우를 화면에 보여줄것인지 말것인지를 지정하는 값.

MSG msg ▶메시지 구조체.
====================================
typedef struct tagMSG{
 HWND hwnd; //윈도우핸들.(특정윈도우를 식별할때 핸들로 식별함)▶값
 UINT message;//핸들의 UINT형의 message로 전달됨
 WPARAM wParam;- 메시지 파라미터(매개변수,인수,인자)
 LPARAM lParam;- 메시지 파라미터(매개변수,인수,인자)
 DWORD time;- 메시지가 전달된 시간(시스템시간)
 POINT pt;-포인터 구조체 (x,y) 모니터상의 표시좌표 ↓y →x 
#ifdef _MAC
 DWORD lPrivate;
#endif
}MSG, *PMSG,NEAR *NPMSG,FAR *LPMSG;

===================================

HACCEL hAccelTable ▶단축키 테이블
<리소스뷰 ▶ HellowWorld▶HelloWorld.rc▶Acceletator▶IDC_HELLOWORLD(단축키테이블)

LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING)
▶IDS_APP_TITLE - 선언부에 가면 그냥 값이들어가있고, 이값을 로딩을해서 전역변수로 선언되어있는 szTitle(TCHAR타입 MAX_LOADSTRING(100개-define) 선언)
▶ 리소스 뷰에서 String Table 안에 보면 IDS_APP_TITLE를 값으로 따지면 103번 그것을 로딩하면 HelloWorld값이 버퍼에저장
   :다국어 지원때문에 리소스이름으로 넣어둠.


MyRegisterClass(hInstance)▶윈도우의 RegisterClassEx를 호출하는것이 목적.Class▶등급  c++의 클래스 뜻이아님.
윈도우 스탈일, 레지스터, 아이콘,마우스포인터,배경색,메뉴,윈도우이름-리소스뷰(IDC_HELLOWORLD(icon/Menu)
wcex.lpfnWndProcWinProc등록되었다는것은▶ Msg-OS-메세지큐-처리(WinProc)<호출하지는않음>-수동적으로 OS에의해 호출되어짐

UINT▶unsigned int 
CALLBACK▶Call Convention(함수호출 시 스텍에 저장할때 어떻게 넣을꺼냐는것)<_stdcall>

WM_COMMAND: ▶ 어떤키를 눌렀을때 발생한 메세지를 처리


InitInstance(hInstance, nCmdShow)▶ CreateWindow함수를 직접 호출
===========================================================
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
       CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL,NULL, hInstance,NULL)
===========================================================
CreateWindow▶윈도우 핸들을 리턴
WS_OVERLAPPEDWINDOW▶ WS: 윈도우 스타일 OVERLAPPEDWINDOW:중첩해서 쓰는 윈도우(가장기본적인윈도우)

WM_PAINT▶윈도우를 다시 그릴때 사용
WM_DESTORY▶ 종료를 눌렀을때 불림.

'MFC' 카테고리의 다른 글

비트맵과 이미지 처리  (0) 2014.03.17
키보드 입력  (0) 2014.03.17
MFC코드의 기본 구조  (0) 2014.03.17
Posted by 레이드리안
|