삽질의 현장/- MFC

#002_MFC_View (기본적인 입출력)

shovelman 2015. 10. 15. 20:11


안녕하세요 삽잡이입니다.


이번시간에는 View 클래스에서 놀아보려고합니다...

즉, I/O... 유저 인터페이싱을 한다 이겁니다.


MFC에는 메시지 핸들러 함수가 있습니다.

이 메시지 핸들러 함수는 윈도우 메시지가 발생시 호출되며, 

우리는 재정의한 함수를 호출하여 우리가 작성한 코드로써 윈도우 메시지 처리를 할 수 있습니다.


예를 들어 '마우스 왼쪽 버튼 클릭'에 대해 

메시지 핸들러 함수를 재정의하여 해당 윈도우 메시지가 발생시 어떻게 처리를 할지 

구현할 수 있다는 소리입니다.


 

API에서 사각형을 그리려면 DC를 만들어야됬던 기억이 나십니까...

어디에 그릴지에 대해서 정했다면 해당 위치에 대한 DC를 구해야됬었습니다.


윈도우를 관리할 수 있도록 만든 객체와 C++ 객체를 혼동해서는 안됩니다.

즉, APP, Main Frame, View, Document는 윈도우를 관리하도록 만든 객체입니다.

API에서는 윈도우를 컨트롤하기 위해 즉, 윈도우를 관리하기 위해 객체를 얻으면 됬었습니다.

MFC도 마찬가지입니다.


사각형을 그린다고 했었죠...

우리가 API에서 GetDC를 사용했듯이, MFC에서는 CClientDC를 사용합니다.

CClientDC를 통해서 '보여주는 윈도우'에 대한 DC를 얻겠다는 뜻입니다.


메시지 맵이라는 것을 아십니까?

이는 API에서 배운 내용중 윈도우 프로시저 함수 안 

switch case 문에 있던 여러 윈도우 메시지지 처리를 기억해보시면 금방 이해하실 수 있습니다.



이 메시지 맵들은 윈도우 메시지와 핸들러 함수와 연결을 해주는 역할을 합니다.

메시지에 대한 매핑이라는 뜻을 가졌습니다.

만약, 우리가 만든 함수가 있다면 수동으로 매핑을 시켜줘야겠지요...

수동으로 해주게 되면 복잡합니다...

하지만, MFC가 무조건 지향하는데로 코드를 구현하는 것이 아닌,

내 나름대로 코드를 관리하고 구축할 수 있다는 사실을 알 수 있게 됬습니다.


메시지가 발생했을 때 호출되는 메소드,

메시지가 발생했을 때 함수와 연결시켜주는 일을 메시지 맵이 한다 이겁니다...

전처리 코드일 뿐입니다... '이 메시지가 호출되면 이 함수를 호출하라!'...

함수 포인터를 사용해서 자동으로 연결 시켜주는 것일 뿐이니 어렵게 생각하시지 않길...(...)


'::' 연산자는 전역 변수, 전역 함수를 뜻합니다.

따라서 같은 이름의 함수일지라도 멤버 함수가 될 수도, 전역 변수가 될 수 있다 이겁니다.

명시적으로 '::'를 붙이고 함수를 호출할 경우 전역 함수를 호출합니다.



윈도우에는 핸들이 있습니다.

따라서 화면에 그리기 위해서 핸들이 필요한데

this->m_hWnd 와 같이 해당 윈도우의 핸들을 구할 수 있습니다.

하지만, 맴버 변수는 객체 지향에서 함부로 사용해서는 안됩니다.

따라서 GetSafeHwnd() 와 같은 함수로 대체할 수 있습니다.



MFC는 Framework 클래스를 제공해주기 때문에 

API를 배울 때와 달리 비교적 쉽게 사용할 수 있습니다.

하지만, MFC는 API 라이브러리를 기반으로 만들어진 API이기 때문에,

API를 똑같이 가져다 쓸 수 있다는 사실을 기억하시길 바랍니다.


OnDraw() 함수는 Paint 메시지가 들어올 때 마다 호출되는 함수입니다.

해당 함수는 다시 그려줄 필요가 있을 때, 

인쇄를 다시 할 필요가 있을 때 사용하기 위해서 만들어진 함수입니다.

따라서 해당 함수의 인자만 바꿔주면 화면, 프린트... 골라서 그려질 수 있습니다.


아무튼...

Paint 메시지가 발생한다면 OnDraw() 함수가 호출된다 이겁니다.

그런데 부모 클래스에는 OnPaint()라는 함수가 있고, 이 클래스에서 OnDraw() 함수를 호출합니다.

Painting을 하기 위해서 부모에서 OnDraw()를 호출하게 되는 것이구요...


원래는 핸들러 함수를 만들어 OnPaint() 함수를 사용합니다.

OnPaint() 함수가 호출되면 OnDraw() 함수가 호출되지 않습니다.

그 이유는 OnPaint() 함수의 부모가 OnDraw() 함수를 호출해주는데,

오버라이드를 해버렸기 때문입니다.


아무튼...

우리가 이전에 CClientDC를 통해 DC를 얻었습니다.

그런데 OnPaint() 함수에서는 오직 CPaintDC를 사용합니다.

정리하자면, CPaintDC는 WM_PAINT 메시지에서 사용하고,

CClientDC는 그 외에 부분에서 사용한다 이겁니다.


지금 언급했던 OnLbuttonDown()함수나, OnPaint나 모두 

코드가 정의된 객체의 맴버 함수라고 볼 수 있습니다.

화면에 출력을 위해서는 'CView' 클래스로부터 만들어진 객체에

위의 멤버 함수들이 필요합니다.


자.. 우리가 만약 해당 함수들을 통해 화면에 무엇인가 그린다고 해봅시다...

View 객체가 윈도우 클라이언트 영역과 연결되있는데,

View 객체를 변경한다는 소리는 클라이언트 영역의 윈도우를 변경한다는 소리가 됩니다.

API에서는 윈도우를 변경하기 위해서 해당 윈도우 핸들이 필요했었습니다.

그런데 MFC에서는 작업을 할 수 있는 최소한 2개의 윈도우가 뜨게 됩니다...

부모 윈도우와 자식 윈도우...

즉, 클라이언트 영역의 View가 두개 뜬다는 소리인데

이는 Frame 객체와 View 객체는 뗄레야 뗄 수 없다는 소리입니다.


따라서 View 객체만을 가지고도 'GetParent()' 함수를 통해 

Main 윈도우의 핸들을 얻을 수 있다 이겁니다.


어찌됬건...

OnLbuttonDown() 함수, OnPaint() 함수에 대해서 알아봤으니...

조금 그리기에 대해서 생각해보겠습니다.


GUI는 대부분 사용자의 Input을 받아들이고

그 Input에 대한 데이터를 어떻게 관리하고 보관할지,

그리고 사용자에게 어떻게 보여줄지에 대해서 생각하는 것이 

GUI의 대부분이라고 할 수 있습니다.


따라서 View 객체에는 보여주는 역할에 대해 충실하고,

데이터 보관에 대해서는 Document 객체에 맡기며 

철저한 분담이 필요합니다.


데이터가 View간에 sync가 이뤄지도록 해야한다 이겁니다.

데이터가 View에 있다면 여러모로 비효율적일 수 있다 이거지요...

따라서, View와 데이터를 분류시켜야합니다.


이말을 하는 이유는 MFC는 View와 Document를 결합시키는 메커니즘이 있기 때문입니다.



자... 결과적으로 망했습니다...


제가 봐도 뭔말인지 곱씹어 봐야하겠군요...

하... MFC 어렵습니다... 너무 대충 봐서... 흙...


다음시간에 뵙겠습니다.

이상 삽잡이였습니다!



'삽질의 현장 > - MFC' 카테고리의 다른 글

#006_MFC_Control, Value형 변수  (0) 2015.10.19
#005_MFC_Document Template 설명  (0) 2015.10.19
#004_MFC_동적 배열 CArray 설명  (0) 2015.10.19
#003_MFC_메모리의 구성  (0) 2015.10.16
#001_MFC_Intro  (0) 2015.10.15