본문 바로가기
Education/Bit 18th

MFC 개념 잡자!

by ★용호★ 2009. 9. 2.

객체지향적 프로그래밍에서는 프로그램을 객체를 기준으로 나누고 이를 좀더 작은 객체로 나누는 식으로 프로그램을 세분화하고 이 객체를 표현한 클래스를 이용하여 프로그래밍 한다고 하였죠? 게다가 무엇을 객체로 보느냐는 전적으로 프로그래머 맘대로 라로 하였습니다.
그럼 여러분은 윈도우 프로그램을 객체로 세분화 할 때 도대체 프로그램에 무엇을 객체로 정하실 겁니까?
아~ 벌써부터 의견이 분분하군요.. 아무리 프로그래머 맘대로 라고 하였지만 효율적인 방법은 있다고 하였죠?
MFC는 클래스 라이브러리고 각각의 클래스는 객체를 표현한 거 겠네요? 그럼 MFC는 누가 만들었죠?
MS사에서 만들었죠 그러니 MFC(Microsoft Foundation Class)라고 졌겠죠..
그럼 MS사는 윈도우 프로그램을 세분화 할 때 무엇을 객체로 봤는지를 알면 MFC를 그런대로 이해할 수 있겠네요..그럼 한번 봅시다.

MS사는 프로그램의 객체를 크게 4가지로 구분하였습니다.
먼저 눈에 보이는 것부터 설명하면 윈도우가 있지요, 타이틀바도 있고 시스템메뉴도 있고 메뉴도 있고 툴바도 있고, 상태바, 스크롤바등이 있는 윈도우 정학히 말하면 윈도우 틀을 객체로 볼 수 있겠네요..
그 다음에 보이는 것은 대부분 흰 바탕에 글씨도 쓸 수 있고.. 그래프로 그릴 수 있고..아니면 입력한 내용을 시트형태로 보여주던가 그래프 형태로 보여주던가.. 그냥 글자만 보여주던가 하는 입력 또는 출력의 기능을 다 가질 수 있는 클라이언트(Client)영역인데 이를 객체로 볼 수 있겠네요..
그리고 눈에는 보이지 않지만 실제로 데이터를 처리하고 저장하고 하는 부분이 있을 수 있겠죠? 그럼 이것도 객체로 볼 수 있겠구요..
마지막으로 역시 눈에 보이지 않지만 위의 설명한 세 개의 객체를 묶어서 프로그램을 구동시키는 부분이 있어야 할 것 같네요.. 그러면 이것도 객체로 보면 되겠네요..
물론 이것말고도 세세하게 들어가 보자면 더 있을 수 있겠지만 대충 이 정도가 있다고 생각해도 큰 무리는 없습니다.
위의 네 가지를 객체로 보고 프로그램을 크게 세분화 한 것이 MS사가 프로그램을 객체로 세분화하는 방법입니다. 그러면 MS사가 만든 MFC도 위 네 가지 객체를 중심으로 클래스 계층구조를 가지고 있겠군요..
계층구조.. 생각나시죠? 실제로 MFC를 보면 위의 네 객체의 속성을 가지고 있는 클래스를 중심으로 이에 파생된 수백개의 클래스들이 계층구조로 이루어져 있습니다.
시작 단계라서 그런지 MFC도 별거 아닌 것 같군요.. 위에서 맨 먼저 말한 객체 즉 윈도우틀(객체)를 C라는 클래스로 구현되어져 있고,, 두 번째로 클라이언트영역(객체)는 CView라는 클래스로 구현되어져 있습니다. 그리고 세 번째로 자료를 처리 저장하는 부분(객체)은 CDocument라는 클래스로 구현되어져 있습니다. 마지막으로 이들 세 개의 객체를 묶어주고 프로그램을 구동시키는 부분(객체)은 C라는 클래스로 구현되어져 있습니다. 좀전에 때 이를 사용하면 화면에 뭔가 잔뜩 나온다고 했는데 이때 나오는 것이 바로 이 네 개의 클래스입니다.물론 C라는 클래스도 있지만 현단계에서 뭐 그리 중요한 것은 아닙니다.
만들고자하는 프로그램마다 약간의 차이는 있겠지만 이 네게의 클래스가 없으면 윈도우 프로그램을 만들 수 없다는 얘기겠죠.. 그럼 위의 네 개의 클래스는 모든 프로그램을 만드는 부분에서 공통적으로 쓰이는 객체이니까 이걸 먼저 파악하는게 MFC를 파악하는 순서가 되겠네요.. 그러면 앞에서 설명한 모든 윈도우 프로그램에 기본이 되는 4개의 클래스를 중심으로 설명해 나가도록 하겠습니다.
C, CView, CDocument, C 라고 하는 이 4개의 클래스는 대부분의 애플리케이션 개발에 공통적 쓰인다고 했지요? 왜 그렇죠? 지금 설명이 다시 원점으로 돌아왔는데.. 처음에 이 개념을 확실히 잡아놓고 가지 않으면, 나중에 좀더 세부적인 사항들을 공부하게 될 때 모든게 헷갈리게 되는까요..확실하게 집고 넘어갑시다.
먼저 MS사가 프로그램을 객체로 세분화할 때, 프로그램의 객체를 무엇무엇으로 정하였죠?
네~~, 모든 윈도우 프로그램에 공통적인 윈도우와 클라이언트 영역 그리고 이를 처리하는 부분과 이들 3부분을 묶어주고 프로그램을 구동시키는 부분해서 프로그램을 이루고 있는 객체를 크게 4가지로 나누었죠? 그렇다면 이 프로그램 객체를 클래스로 구현한 것이 차례대로 C, CView, CDocument, C 클래스 라고 했죠? 그러니 당연히 이들 4개의 클래스들은 모든 윈도우 프로그램에 쓰이겠죠? 너무나 당연한 얘기를 하였습니다. 그렇지만 중요합니다. 제 심정으로는 한번더 반복해서 여러분들이 완전히 기억하고 넘어가셨으면 좋겠지만.. 그러면 너무 지문낭비가 심하겠죠? 통신비도 만만치 않은데...
그럼 앞부분에 MFC가 클래스들의 계층구조로 이루어졌다고 말씀드렸습니다. 그럼 MFC의 개략적인 계층구조와 위의 4개의 기본적인 클래스들이 이들 계층구조에 어디쯤 해당되는지 볼까요?
먼저 여러분들의 이해를 돕기 위해 SDI(Single Document Interface)프로그램을 기준으로 설명하겠습니다. 갑자기 SDI라는 말이 툭 튀어 나오니 당황하시는 분이 있을지 몰라서 아주 간단히 설명하겠습니다.
윈도우 프로그램은 크게 SDI, MDI로 나누어 생각해 볼 수 있습니다. 여러분 프로그램을 사용하다 보면 프로그램 메뉴에 창(Window)이라는 메뉴가 있는 프로그램을 자주 보십니다. 그 메뉴에는 어떤 내용이 들어있냐 하면 바둑판식, 타일 등의 서브메뉴가 있는데요.. 벌써 눈치 채셨겠지만 프로그램내에서 윈도우 창을 여러개 만들거나 불러들여 작업할 때 이런 창들을 정렬시키는 방법이지요? 그럼 윈도우 창이 하나밖에 필요하지 않는 프로그램이 있을까요? 물론 많지요... 위의 프로그램내 2개이상의 새창을 만들거나 불러들일 수 있는 프로그램은 MDI라고 하구요... 단일창만을 가지고 있는 프로그램을 SDI 프로그램이라고 합니다. 사실 창이라고 얘기해도 되지만 템플릿(Templete)라는 말을 쓰더군요.. 똑 같은 얘기지요.. 어쨌든 프로그램이 SDI,MDI라고 나뉠 수 있으니 왠만한 윈도우 프로그램용 클래스를 다 가지고 있는 MFC도 이들을 지원함은 당연하겠지요? 하지만 이들을 뭐 SDI_MFC, MDI_MFC라고 따로 가질 필요가 있겠습니까? 상식적으로 생각해 봐도 그럴 필요가 전혀 없겠죠? 하지만 MDI 프로그램을 만들려면 SDI보다는 뭔지는 모르겠지만 뭔가 MDI를 만들 수 있도록 도와주는 클래스 들이 있을 것 같지 않나요? 예 그렇습니다. 그래서 뭐 그리 차이는 없겠지만 SDI를 기준으로 MFC계층구조와 4개의 기본적인 클래스들을 설명한다고 하면 MDI를 만들 때 필요한 클래스들은 일단 생략하고 설명하겠다는 얘기입니다.. 아시겠죠? 이해가 안가시는 분들은 그냥 모른척하고 지나가세요.. 어차피 알게될.. 알아야 할 얘기니 뒤에 가서 또 나오겠죠?

간단히 MFC계층구조를 볼까요?

Object


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


| | |
- C - CFile - C
| | | |
| - C - CDC - C
| | | | |
| | - C - C - C
| | | |
| - CDocument - CMenu - C
| |
- CWnd - CDatabase
| |
- C - C
| |
- CView - C
| |
- CDialog - CArray
| |
- C - CList
| |
- 여러 컨트롤 클래스들 - CMap

보신 소감이 어떠십니까? 낯설기는 하지만 복잡하다는 생각은 별로 없으시죠? 사실 위의 계층도는 제가 간단하게 요약한거에 불과합니다. 이를 자세히 보고 싶으신 분은 아래를 클릭하세면 inforview에서 볼 수 있는 내용을 볼 수 있습니다. 그림이 조금은 클테지만 참고하시면 좋을 것 같습니다.



MFC계층도Categories

MFC 계층도 (그림이 상당히 큼)

위의 계층도를 간단히 설명하겠습니다. 다음 페이지에서 할까 하다가 저 그림을 보면서 해야 하기 때문에 어쩔 수 없이 다소 길어 지더라도 이번 페이지에서 마무리를 지어야겠네요..
MFC의 클래스를 크게 나누면 CObect에서 상속받은 클래스와 그렇지 않은 2개의 클래스로 나눌 수 있습니다. 위의 제가 그려놓은 계층도는 보시는 것 같이 Object에서 상속받은 클래스들입니다. 상속받지 않는 클래스들을 보시려면 MFC계층도를 참고하세요...
CObject에서 상속받은 클래스를 범주별로 보면 기본적인 애플리케이션 아키텍쳐에 속하는 부분이 C 부분이고 특히 C클래스는 윈도우 메시지와 관련된 클래스입니다. 윈도우가 메시지 구동방식이란 것은 앞에서 설명했지요.. 그와 같은 것을 지원해 주는 클래스라는 얘기입니다. 그 밑에는 CWnd라는 클래스부분이 있네요.. 클래스의 이름을 살펴보면 아시겠지만.. 윈도우(창)과 관련된 클래스이겠죠. 그리고 파일과 관련된 CFile 클래스, 그래픽관련 클래스인 CDC, C가 있고, Database관련 클래스가 두 개 보이는데 CDatabase는 ODBC 데이터 베이스를 지원해 주기 위한 클래스이고, C라는 클래스는 DAO 데이터베이스를 지원하기 위한 클래스입니다. 그다음은 윈도우 소켓프로그램과 관련된 C이라는 클래스가 보이고 그 밑에있는 CArray, CList, CMap은 전부 자료구조(data structure)와 관련된 클래스들입니다. 그리고 맨 오른쪽에 있는 클래스들은 인터넷 관련 클래스들입니다. 그냥 대충, 아주 대충 설명하였는데.. 어떤 범주의 클래스들이 있는지만 보고 넘어가시면 될 것 같습니다. 우리가 여기서 주의 깊게 봐야 할 부분은 앞에서 모든 프로그램에 기본적인 4개의 클래스들입니다. MFC계층도에서 어디쯤에 위치하고 있는지 잘 보십시오.. 빨간색으로 되있으니까 보기 편하실 겁니다.
MFC계층구조와 위 4개의 기본 클래스에 대한 자세한 얘기는 다음페이지에서 하죠.. 넘어갑시다.

10.AFX(Application Frameworks)

앞장에서 대충이기 하지만 4개의 클래스(C,CView,CDocument,C)가 윈도우 프로그래을 만들 때 기본이 되는 클래스라고 얘기했습니다. 그렇다고 이 4개의 클래스를 달달 외워야 하나요? 그럴 필요 있겠습니까?
앞에서 MS사가 프로그램을 어떠어떠한 객체로 나누었다고 했지요? 윈도우틀, 클라이언트 영역(쉽게 허연부분),그리고 눈에 보이지 않는 데이터를 처리, 저장하는 부분 또? 이 세 부분을 묶어서 프로그램을 구동시키는 부분... 뭐 대충 이렇게 나누었다고 했죠? 클래스 이름을 기억하는 것도 중요하겠지만 이름정도야 어딜봐도 나오니 이들 클래스가 어떠한 객체를 표현해 주고 있는지를 알고 있는게 더 중요합니다. 이 4개의 클래스가 윈도우 프로그램을 개발하는데.. 기본골격이 되기 때문에 이를 흔히 AFX라고 부릅니다. 그러니 AFX라는 말에 지래 겁먹을 필요는 전혀 없습니다..
그럼 이들 클래스가 무엇을 표현했는지는 이 정도면 명확하게 알았으니.. 몇 가지 궁금증을 풀어볼까요?
여러분들은 MS사가 프로그램을 객체로 세분화하는 과정에서 왜 프레임윈도우(윈도우틀)와 뷰(클라이언트 영역)를 구분했다고 생각하십니까?
답은 간단히 객체지향적으로 만들기 위해서입니다... 답이 좀 그렇죠? 그럼 생각해 봅시다.. 윈도우프로그램을 실행시켜보면 윈도우(창)이 생기죠? 그럼 이놈이 도대체 어떤일을 합니까? 우리는 마우스를 이용하여 윈도우를 최소화 시킬 수도 있고,최대화 시킬 수도 있습니다. 또 타이틀바 부분을 클릭하여 드래그(drag:끌기)면 윈도우가 움직입니다.. 또 허연부분은 이러거 저런거 막 보여주죠? 물론 워드프로세서,그래픽 도구같은 응용프로그램은 이 허연 부분(클라이언트영역 = 뷰)에서 입력도 할 수 있죠... 그렇지만 결과적으로 입력한 내용을 보여주죠?
윈도우를 최대화 시켰을땐 텍스트로 보여주다가 윈도우를 최소화 시키면 그래픽으로 보여주는 프로그램 보셨어요? 어떻게 보여주는냐는 윈도우 자체를 제어하는 부분과는 아무 연관없이 작동합니다. 즉 윈도우 자체를 제어하는 부분과 데이터를 보여주는 부분이 크게 관여치 않고 독립적으로 움직인다는 얘기입니다. 이는 당연히 프로그램을 만들 때 이런식으로 작동하도록 만들었을테니 이런식으로 작동하겠죠? 이렇듯 객체지향적이라는 것은 하나의 객체(Object)가 철저하게 자기 역할만 한다는 것이죠...
자기가 할 일 예를들어, 윈도우틀(C)가 할 일을 클라이언트 영역(CView)이 대신하게 한다든가... 윈도우틀(C)가 이거저거 다 하도록 프로그램을 만들면 안된다는 얘기죠... '왜 안될까?'는 각자 생각해 보세요..
그럼 두 번째 궁금증을 해결해 볼까요?
어떠어떠한 데이터를 처리한다면 당연히 CDocument클래스가 하도록 만들어야겠죠? 좀더 정확하게 말하자면 CDocument클래스에서 파생된 C(이름은 프로그래머 맘데로지만요..기반클래스가 무언지를 시각적으로 알기위해서 흔히 이렇게 작명합니다)를 상속성과 오버라이딩등을 이용하여 만들어야겠죠.... 그런데.. 왜 도큐먼트와 뷰를 구분했을까요?
만약, 처리된 데이터를 보여주는 방법이 하나뿐이라면 궂이 나눌이유는 없을 것 같습니다... 그러면 이 뷰와 연결된 도큐먼트가 무엇인지를 알 필요도 없이 같은 클래스내에서 간편하게 만들 수 있을 것 같지 않나요? 하지만 우리는 멀티미디어 시대에 살고 있습니다.. "안녕하세요?"라는 데이터를 처리하여 보여주는 방법이 그냥 텍스트로만 "안녕하세요?"뿐이겠습니까? 아니죠... 음성으로 "안녕하세요?"할 수 도 있고, 아니면 글자애니메이션(예를 들어 "안녕하세요?"화면을 마구 돌아다닌다든지..)등등 표현할 수 있는 방법은 수도 없이 많습니다... 엑셀 같은 프로그램에서도 같은 입력내용으로도 데이터시트(sheet)로 보여줄 수도 있고 그래프(graph)로도 보여줄 수 있죠? 이는 어떻게 가능할까요? 이는 하나의 도큐먼트가 여러개의 뷰를 가질 수 있어야 가능한 얘기입니다... 그러니 도큐먼트와 뷰를 다른 객체로 나눠나야..이를 실현할 수 있을 거 아닙니까... 또 다른 이유 중에 하나는 이런저런 기능을 많이 가진 클래스보다는 단순한 클래스로 만드는게 훨씬 더 효율적이라는 측면도 조금은 있습니다.. 어찌됐건 간에.. 이 나뉘어진 객체(Object)들은 철저히 역할분담을 하여 자기역할만 충실하게 합니다.. 자기가 해야 할 일을 않한다거나... 다른 객체가 해야할 일을 자기가 하는 일 따위는 있어선 안돼죠.. AFX는 다음 장에서 자세히 다루겠지만.. 기본정신은 그렇습니다.. "철저한 역할분담 및 성실한 역할 수행" 무슨 캠페인 같군요...
짧은 내용을 설명하면서 객체와 클래스라는 말이 나왔습니다... 아직도 혼돈 되십니까? 노파심에 다음과 같이 정리하였습니다.

객체(Object)
MFC 클래스(Class) =AFX

윈도우틀 생성,제어 부분
C

클라이언트영역(뷰) 부분
CView

데이터 처리,저장 부분
CDocument

위세 개 엮어 프로그램구동 부분
C


컴퓨터를 켜시고 비주얼C++을 실행시키세요.. 강좌는 VC++6에 맞춰하겠지만..VC++5를 가지고 계신 분들이 상당히 많으시기 때문에 예제나 실습등은 공통되는 VC++5로 하겠습니다... 괜찮으시죠?
자~ 실행이 됬으면..ctrl+N이나 [파일]메뉴에서 [new]를 클릭하시면 창이 나옵니다.. 앞에서도 한번해봤으니 벌써 두 번째 인데요.. 프로젝트명을 원하시는데로 적으세요.. 저는 My라고 하죠..그리고 [프로젝트]탭에서 MFC (exe) 선택한다음 Ok! 그러면 영어로 뭐라고 물어보죠? "What type of Application would you like to create?" 어떤 타입에 응용프로그램을 만들꺼냐라고 묻는거죠... 밑에 라디오버튼있는 곳을 보면 Single Document, Multiple Document, Dialog based라고 묻죠? 이게 전에 설명한 윈도우 응요프로그램 유형인 SDI로 할꺼냐 MDI로 할꺼냐를 묻는 것입니다. 물론 세 번째 항목은 Dialog based라고 되있지만 Dialog based는 사실 별거 아니니 나중에 꽤 나중이겠지만.. 예제를 통해서 설명해도 전혀 무리는 없습니다..보면 다 아니까요..
그럼 우린 우선 SDI로 갑시다... 그리고 finish를 클릭하고 ok한번 클릭하면 짜잔~~~~워크스페이스(왼쪽 트리형식의 창)에 뭐가 막 나오죠? (앞으로 클래스뷰)탭을 보면 라는 말그대로 나의 클래스들이 있죠?

+모양된건 다 클릭하여 전체가 다 보이도록 해보십시오..
여러분이 한것에 비해 너무 엄청난 클래스들과 멤버변수, 멤버함수들이 만들어져 있습니다.

찬찬히 살펴보세요.. 먼저 C라는 클래스가 보이죠? 별거 아닙니다..만들제품 제품정보등을 사용자들에게 보여주기 위한 것일 뿐이지 프로그램의 대세에는 전혀 영향을 미치지 않으니 무시해 버리세요.. 그다음에는 C라는 클래스가 보이시죠? 그럼, 이 클래스의 생성자함수와 소멸자 함수를 찾아보세요.....
역시! 클래스명과 같은 이름의 함수가 생성자 함수니까..C()이 생성자 함수이고 ~C()함수가 소멸자 함수지요? 그럼 생성자함수인 C()을 더블클릭해 보세요..오른쪽 창에 뭐가보이죠? 뭐가 보입니까? 다음과 같이 되있을겁니다.

C::C()
{
// TODO: add member initialization code here
}

C::~C()
{

}

에게~~~안에 아무내용도 없네요.. 이부분은 여러분들이 짐작했다시피 my.cpp라는 소스파일에 있는 C의 정의부분 즉 멤버함수의 정의부분중 생성자함수와 소멸자함수의 정의부분입니다.. 아무내용도 없다는 건 아무기능도 하지 않는다는 얘긴데 뭐하러 이렇게 수고스럽게 가 만들어 두었을까요? 꼭 기억하세요!!!! 비주얼C++를 공부하다보면..아니 더 정확히 말해서 MFC를 공부하다보면..음 이 클래스는 이러 이러한 일을 하는 클래스군..쩝..이 멤버함수는 이러이러한 일을 하는군..쩝..그렇군..쩝.. 하게됩니다.. 그런데 초보자들은 특히, C를 조금 할줄 아시는 분들은 입문서등에서 예제등을 통해서 설명하는 부분에서 책에서 하라는 데로 부분부분 이해하고 직접 코딩도 하고 컴파일해서 실행파일 만들어 실행시켜보면 다 잘됩니다..겉보기엔 뭔가 되는 것 처럼 보이지만..이런일들을 계속해 나갈수록 점점 깊이 있는 얘기를 접할수록 MFC라는 놈이 점점 알 수 없는 존재가 되버립니다.. 그중 가장 큰 이유가 "나는 별로 한게 없는데..실행해보면 정말 엄청나다"는 것입니다.. 여러분들도 지금 my라는 프로젝트를 F7,F5차례로 눌러 실행시켜 보세요... 기가 막힐 노릇이죠..그런데.. 처음에는 세세한 부분까지 신경을 안쓰니까 잘 모르시겠지만.. 세세한 부분들을 생각해보면 정말 알 수 없거든요.. 예를 들어 실행을 시켜보면 윈도우가 생성되고 메뉴도 있고 툴바도 있고 상태바도 있습니다. [File]메뉴에 [open]을 클릭하면 파일열기 공통다이얼로그 박스가 나옵니다.. 파일을 선택해도 불러지지는 않지만.. 대충이런식으로 보면 음~~~ 윈도우가 메시지 구동방식이라고 했으니 여길 클릭하면 이 메뉴가 클릭됐다는 메시지가 발생하고 그러면 프로그램이 이 메시지를 받아 공통다이얼로그 박스가 뜨도록 설계한거군...라고 생각이 들면서 자신감이 생깁니다.. 하지만, 툴바를 클릭해서 다른곳으로 드래그 시켜보세요.. 툴바가 띠어졌다..붙어졌다 하죠? 윈도우도 최소화/최대화단추를 이용해서 크게 작게 또는 모서리 부분으로 마우스 포인터를 가져가 임의의 크기로 만들 수도 있습니다..
더 세세한 부분까지 얘기해 볼까요? 마우스가 윈도우창 위를 지나면 마우스가 윈도우 위를 지나가고 있다는 메시지가 수도없이 많이 나오겠죠? 이건 또 어떻게 처리되겠습니까? 마우스포인트를 움직이면 마우스포인터의 잔상이 남지 않고..지나간 자리의 마우스포인터 모양은 없어지고 다시 허연 클라이언트 영역이 보입니다.. 이런 화면복원등도 프로그래머가 직접해줘야 하는거지요.. 이런저런 생각을 마구하다보면 단지 My만을 입력한 우리는 바보가 된 느낌이 들죠... 에게 농락당한 느낌이 든다니까요...정말로요...
너무 얘기가 쓸데없이 장황해졌는데...얘기하고자하는 바는 간단합니다.. MFC를 학습할 때는 방향과 포인트를 잘 잡아야 한다는 것입니다..
그냥 클래스인 경우 기능이 뭐고 어떤 멤버가 있고, 멤버함수인 경우 어떤 기능을 하고 어떤 인자를 받고 어떤 타입의 데이터를 넘겨주는지에 관심을 집중시키면 안된다는 겁니다.. 물론 이런 것들이 중요한 것은 말할 것도 없겠지만.. 이런식으로 학습하는 것은 C 라이브러리를 공부하는 것과 다를 바가 없지 않습니까? 그러니 클래스인 경우 계층구조상 어디에 위치하고..기반클래스가 뭐이며..등의 클래스의 상속성과 관련된 것들에게 집중을 시키고.. 함수의 경우에는 이 함수가 언제 호출되는 함수인가에 관심을 먼저 집중하여야 한다는 것입니다.. 물론 저도 이러한 관점에서 설명해 나가겠습니다..

10.AFX(Application Frameworks) (계속2)

그럼 내용도 없는데데..왜 굳이 함수 부분이 정의되있을까요...
그것은 아무일을 하지 않더라도 호출은 된다는 말입니다..

가 바보가 아닌이상 사용되지도 않는 함수를 정의하겠습니까?
클래스를 만들기만 해놓으면 아무소용 없다고 했지요? 클래스의 인스턴스를 만들어 이 인스턴스를
사용해야 클래스를 만든 보람이 있는 것입니다..
함수도 마찮가지예요.. 만들어 놓기만 하면 뭐하겠습니까.. 사용(호출)이 되지 않으면 아무소용
없는거 아닌가요?

생성자함수와 소멸자함수도 현재로선 아무일도 하지 않지만 프로그램이 실행하는 과정에서
호출이 된다는 말입니다...

그럼 이 성자와 멸자는 언제 호출될까요? 앞에서 설명했는데.....

생각안나시면..다시 앞부분을 보세요..여기서 다시 장황하게 설명하는건 무리인거 같습니다.

생성자함수는 클래스의 인스턴스가 생성될 때 호출되고 소멸자함수는 인스턴스가 소멸될 때
호출되고 클래스의 인스턴스는 지역변수,전역변수,정적변수중 어떤 변수로 선언되었냐에 따라
생성과 소멸시기가 달라진다고 하였습니다..

만약 우리가 안이 텅비어 있는 생성자함수에 이런저런 기능을 넣어준다고 한다면..
이는 "이 클래스의 인스턴스가 무슨 변수로 선언되었으니까 생성자 함수가 프로그램중 이쯤에서
호출될테니 여기다 이쯤에서 해야할 일들을 넣어주자"라는 생각을 먼저해야 한다는 것입니다..

<꼭꼭꼬옥~ 기억해야할 내용>

일반적인 함수는 함수를 정의하는 부분이 있으면, 반드시 반드시 그 함수를 호출하는 부분이
있게 마련입니다.
그렇기 때문에 우리가 어떤 기반클래스의 어떤 멤버함수를 오버라이딩하여 수정했다고 한다면
우리는 이 파생클래스의 오버라이딩된 멤버함수를 호출하지 않습니다..
왜냐하면, 이 오버라이딩된 함수는 기반클래스에서 호출되고 있기 때문입니다.

MFC를 이용한 프로그래밍이 다 이런식으로 이루어집니다..

즉 MFC는 별다른 일을 하지 않는 함수라도 이럴 때 호출되는 함수, 저럴 때 호출되는 함수등을
각종 상황에 따라 이미 다 만들어 두었다는 얘깁니다..

이렇게 각종상황에 호출되는 함수들이 다 만들어져 있다는 것은 어떠한 상황이 되면 그에
해당하는 함수를 호출하는 프로그램의 틀이 이미 다 만들어져 있다는 것입니다...

그럼 우리는 뭘하면 되겠습니까?


어떤 상황에서 어떤일을 해야되는지를 알고 있어야 합니다..

그다음에 이 상황에서 어떤 함수가 호출되는지를 알아야 합니다.

그리고 이 함수를 오버라이딩해서 거기에 이상황에서 해야하는 일을 넣어주어야 합니다..

위의 내용이 우리가 MFC를 공부할 내용입니다...여기에 초점을 맞추세요...


그럼 흥분을 가라앉히고...다시 클래스뷰를 봅시다..
각각의 클래스 안에는 멤버함수와 멤버변수가 있습니다..어떤 것이 멤버함수이고 어떤 것이 멤버
변수인지는 멤버앞에 있는 아이콘 모양만 봐도 알 수 있습니다.보라색 정육면체가 함수/ 하늘색
정육면체가 변수를 가리킵니다.. 그리고 멤버 앞에 있는 열쇠는 protected난 private로 선언된
변수들이니 클래스내부에서만 참조될 수 있는 변수들이죠...

그런데 C클래스 말고 어떤 클래스가 또 있지요?
예~~ 보시는 것과 같이 C, C, C가 있군요..
그곳에도 전부 생성자 함수와 소멸자 함수가 있죠...

놓치기 쉬운 한가지 Global(전역변수)밑에 뭐가 있습니까?
theApp라는게 있는데.. 이게 도대체 뭡니까?

이것은 C클래스의 인스턴스입니다.이젠 인스턴스까지 만들어 놨군요...
이설명은 다음 페이지에서 하도록 하겠습니다..
그럼 이제 하나하나 클래스를 살펴볼까요?


<노파심>

혹시 C,C,C,C,클래스를 MFC라고 생각하시는 분 있으면 손들어 보세요..
어~~ 꽤 여러분들이 그렇게 생각하시는군요...쩝..

위의 네 개의 클래스들은 각각 MFC의 C,C,CDocument,CView클래스에서 상속받은
파생클래스들입니다..
상속받는 이유가 뭐지요? 그대로 사용할꺼면 그냥 MFC에 있는 클래스를 그대로 사용하면 되는데..
우리가 뭔가 더 넣을려고 하는 거지요..

실행시켜봐서 알겠지만 우리가 간단한 메모장을 만들고자 한다면, [File]메뉴에 있는[Open]을
클릭하면 파일열기 공통다이얼로그 박스가 나오는데..지금은 파일을 열 수 없지만 우리가 파일을
읽어 뷰영역에 보여주는 기능을 넣어주어야겠죠?

이런 기능을 넣어주려면 MFC를 그대로 사용하면 안되니까 상속받아 파생클래스를 만든 것입니다..
그러니 우린 앞으로 멤버변수도 추가하고 함수도 추가하고 기반클래스의 멤버함수를 오버라이딩
하기도 할꺼 아닙니까?

그리고 우리는 아직 아무 인스턴스도 만들지 않았습니다.. 그것은 곧 클래스를 사용하지 않았다는
얘기죠...

아니 클래스를 사용하지도 않았는데..어떻게 실행이 되냐구요?
당연하신 말씀입니다..

하지만 우리가 만들진 않았지만 프로그램시작때 생성되서 종료시 소멸되는 전역변수 theApp란
C의 인스턴스를 가 만들어 놨지 않습니까....
이 인스턴스 때문에 실행이 되는 것입니다..

이에 대한 설명은 차차 할테구요.. MFC에서 상속받은 파생클래스라는 점 잊지 마세요..

MFC의 클래스, MFC에서 상속받은 파생클래스, 인스턴스를 헷갈리기 시작하면 죽도밥도 않됩니다...



Visual C++ 6 강좌(025)



10.AFX(Application Frameworks) (계속3)

AFX의 베일을 벚겨(?)봅시다..

먼저 눈에보이지 않는 객체를 구현한 클래스중에 프로그램을 구동시켜주는 C클래스를
살펴보겠습니다.


1.C

C,CDocument,CView클래스를 묶어 프로그램을 구동시키는 역할을 하는 클래스라고 벌써
설명하였지요?

그럼 먼저 위치확인!!
어디에 있습니까? 아~~뭐하세요..찾아 보셔야죠...직접눈으로 확인하는 습관을 먼저!!

그럼 간략하게 적어보겠습니다.

CObject-> C-> C->C

이것은 C가 어떤 클래스에서 파생되었는지를 보여주고 있습니다.
역시 Class의 대부인 CObject에서 파생된 클래스지요? 물론 CObject에서 파생되지 않은 클래스도
있습니다. 그렇지만 그것은 일부이고..앞으로 설명될 대부분의 클래스는 CObject에서 파생된
클래스들입니다.

C는 CObject에서 파생되었기 때문에 CObject의 내용이 다 있겠죠?
이렇게 따져보면 C는 CObect,C,C의 모든 내용을 다 가진 셈이죠...

그럼 이 클래스가 어떤 일을 하는지 볼까요?
제가 대충 프로그램을 구동시키는 역할을 한다고 하였습니다.
모든게 시작과 끝이 있듯 프로그램에도 시작과 끝이 있습니다.(무슨 철학서에 나오는 문장같군요)
물론 시작과 끝사이에도 뭔가가 있죠...

그럼 프로그램을 구동시킨다는 얘기는 프로그램의 시작과 끝 그리고 그사이에도 일을 한다는 얘기
입니다..
그래서 이 클래스는 프로그램의 시작과 종료를 담당하고 프로그램이 실행되는 동안(즉 종료되기
전까지)메시지를 뿌려줍니다...

그럼 정리!!



프로그램의 시작/종료를 담당

프로그램 시작시 메인프레임 윈도우를 생성시켜줌

프로그램종료시까지(즉, 프로그램을 종료하라는 메시지인 WM_QUIT라는 메시지를 만날 때까지)
메시지를 뿌려줌


앞에서 우린는 를 이용하여 아무일도 하지 않는 윈도우 프로그램을 만들었습니다.
프로그램을 시작하면 윈도우(메인프레임윈도우)뜨지요?
이것을 C 클래스가 한다는 얘기지요...
그리고 우리가 메뉴를 클릭하면, 메뉴가 활성화(색깔이바뀌는 것을 고상한 말로 활성화 어쩌구
하는 거죠..)되지요? 이것은 어떻게 되는 거죠? 예~~ 메뉴를 클릭하면 마우스가 클릭되었다는
메시지가 발생하고 이에 대응하여 호출되는 함수(메시지 핸들러 함수)가 호출되어 이렇게 저렇게
수행을 하는 거죠... 이 윈도우 메시지를 프로그램에게 알려주는 것도..C가 하는 역할
입니다..

또 어떤식으로 프로그램종료시까지 메시지를 뿌릴까요?

다음과 같이 프로그래밍하면 되겠죠....

while(윈도우메시지 != WM_QUIT)
{
메시지를 뿌려라~~~
}

뭐 대충 이런식으로 하면 되겠죠.. 윈도우 메시지가 WM_QUIT가 아닐 때까지 메시지를 뿌려라..
일종의 무한루프지요?

우리가 프로그램을 만든다면 이 C클래스가 필요하겠죠?
C로 충분하다면 그냥 이 클래스를 쓰면 되지만... 우리는 뭔가 바꾸고자 합니다..
당연히 그럴테지요.. 메인프레임 위도우가 뜨기전에 뭔가 하고 싶다면 이 클래스에 그 뭔가 하고
싶은 일을 넣어주어야 할테니까요..
그래서 C라는 이름으로 파생클래스를 만든거 아닙니까...물론 가 알아서 해주긴
했지만..

그리고 앞에서도 얘기했지만 C의 인스턴스가 있죠? 어디에 있죠? 워크스페이스에서 찾아
보세요...Global(전역변수)부분에 있죠?
클래스는 만들기만 해놓아서는 아무 소용이 없죠...사용을 해야 쓸모가 있는것입니다.
그래서 theApp라는 인스턴스를 만들었습니다. 이 인스턴스가 없으면 컴파일을 시켜도 아무것도
없겠죠?..전역변수로 된 이유는 프로그램이 시작하면서 이 인스턴스가 생성되고 종료될 때 소멸
되게 하기 위한거죠.. 계속 반복하니까 이젠 지겨우시죠?

C의 기능을 단순화 시키면 시작-메시지뿌리고-종료 식으로 생각할 수 있습니다..
실제로 이를 하는 멤버함수는 (), Run(), ()입니다
그래서 C는 인스턴스가 생성되면서(프로그램이 시작할 때) 이 멤버함수를 위의 차례로
호출합니다..
그럼 각각의 멤버함수가 하는 일은 무얼까요? 얘기하지 않아도 아시겠죠?
위에 벌써 설명다 했는데...
()는 인스턴스가 생성될 때 해야 하는 일들을 해야겠죠?
이 인스턴스가 생성될 때 해야 하는 일이란 프로그램을 초기화하는 각종 루틴을 말하는 겁니다.
이중 제일 중요한 것은 CView,CDocument,C클래스를 묶는 것이지요..

그럼 Run()은 WM_QUIT메시지를 만날 때까지 메시지를 뿌려주는 일을 하겠지요?
그리고 ()는 프로그램이 종료하기전에 실행되는 함수로 여러 정리루틴을 가지고 있
겠죠....

그래서 C가 하는 일을 간단하게

() -> Run() -> ()로 말할 수 있습니다..




Visual C++ 6 강좌(026)



10.AFX(Application Frameworks) (계속4)

이제 가 만들어준 C의 파생클래스인 C를 잠시 보겠습니다.

C는 C가 가지고 있는 멤버를 다 가지고 있습니다.. 그래서 같은 기능을 합니다..
너무나 당연한 얘기입니다..
그렇다면 클래스를 상속받을 쓰는 문장만 써주면 되겠군요...아래와 같이요..

class C : public C{};

똑 같은 기능을 하니 안에 아무것도 쓰지 않아도 되겠죠... 그럼 확인해 봅시다..
클래스의 선언부분이니 C가 선언되어있는 헤더파일을 보면되겠죠?

헤더파일은 어떻게 봅니까?
워크스페이스밑에 탭을 보면 라는 탭이 보입니다. 이를 클릭하면 Source File,
Resource Files, Header Files 항목이 있습니다.

그냥 보면 알겠지만 소스파일은 cpp확장자를 가진파일들을 모아놓은 항목이고, 리소스 파일은
그림,아이콘,리소스(메뉴바,툴바등)등을 모아놓은 항목이고, 헤더파일은 말그대로 헤덯파일을 모아
놓은 항목입니다..

그럼 헤더파일을 클릭하면 확장자가 h인 여러 파일이 나오는데요...어느 헤더파일에 선언되어
있을까요?
눈치채셨겠지만..My.h라는 파일에 있습니다.. 이를 클릭하면 C를 선언하는 부분이 나옵니다.
기름끼 좍빼서 보면 다음같이 되 있지요..
class CZApp : public C
{
public:
CZApp();
public:
virtual BOOL ();
};

안에 뭐라고 적혀 있네요...이는 가 알아서 넣어 둔건데.. 이를 보면 CZApp()라는 함수
를 오버라이딩 해서 쓰라고 되 있습니다..(주석부분에요..)
그럼 안에 어떻게 오버라이딩되있는지 볼까요?

멤버함수의 내용을 보려면 클래스의 정의부분(=멤버함수의 정의부분)을 보면 되는데...어디서
보면 되겠습니까? cpp확장자를 가진 소스파일을 보면되겠죠?
r.cpp를 클릭해서 보면 아래와 같이 되있습니다.

CZApp::CZApp()
{
// TODO: add construction code here,
// Place all significant initialization in
}


아무 내용도 없네요.. 우리보러 알아서 하라는 얘기죠..알아서 하라는 말은 여기에 뭔가 넣으려면
넣고 말라면 말라는 얘기입니다..그럼 이 함수가 프로그램중에 언제쯤 호출되는 지를 봐서
그 즈음에 해야할 일을 여기에 넣어주면 되는 거죠... 그런데 주석문을 보니 어떤 것들을 넣어야
되는지 대충 알 것 같군요... 영어를 못하면 여러 가지로 고생이죠..
지금 이함수에 대해선 자세히 하지 않겠습니다...지금은 이 함수를 쓸일이 거의 없으니까요..

자~~그럼 파생클래스인 C의 또다른 멤버함수를 볼까요? 여기에 함수가 있군요
이 함수는 기반클래스인 C에서 정의된 함수이기 때문에 써줄 필요가 없을 것 같은데..
써준걸 보니 내용을 수정또는 추가 즉, 오버라이딩해서 쓰라는 친절한 의 짓이군요..

그럼 혹시 가 알아서 적당한 내용까지 넣어놨을지도 모르니까 한번 볼까요?
이 함수 정의된 부분을 찾았습니까?

어떻게 되있나요? 다소 복잡해 보이지요?

또 기름기 쫙빼서 아래와 같습니다.

[My.cpp]

#include "stdafx.h"
#include "My.h"
#include ".h"
#include ".h"
#include ".h"

C::C()
{ };

C theApp;

BOOL C::()
{
C *p;

p = new C(IDR_MAINFRAME,RUNTIME_CLASS(C),
RUNTIME_CLASS(C),RUNTIME_CLASS(C));
(p);

return True;
}

와우~ 뭔말인지 하나도 모르겠군요...

차근히 봅시다.. 위의 #include 문장은 헤더파일을 인쿨루드하라는 얘긴데..
생소한 헤더파일하나가 보이는군요... stdafx.h...

다른건 대충알겠죠? 간단히 예를 들면 .h는 CDocument에서 파생된 C클래스의 선언부분
가진 헤더파일이구요.. 나머지도 마찮가지인에...
stdafx.h라~~~
그런데.. C공부하신 분들은 어디서 많이 본 것같은 모양을 하고 있군요...꼭 "stdio.h"랑 비슷
하지 않나요? 지겹게 나오는 파일이지요.. stdio는 S Input Output의 의미를 가진거였죠?
기본적인 입출력과 관계된 함수들과 상수 매크로 기타등등이 선언된 헤더파일입니다.
예를 들어 화면출력함수인 printf()함수를 사용하려면 반드시 stdio.h파일을 소스파일(***.c)에
포함(include)시켜 주어야 됬었습니다. 만약 인클루드하지 않고 그냥 사용하면 컴파일 에러가
발생합니다..너무나 당연한 얘기였습니다...

이 stdafx.h라는 헤더파일도 C의 stdio.h만큼 중요하고 자주 쓰이는(?) 아니 거의 쓰이는 헤더
파일이니 시간날 때 마다 그 내용을 이해는 안가더라도 눈에는 익숙하게끔 하는 것이 좋을 것
같습니다.. 그렇다고 지금 당자 보실 필요는 없구요...심심할 때요...

stdafx는 S AFX(Application Frameworks)의 약자이구요.. MFC 클래스들의 선언을 비롯해서
상수,매크로정의등 MFC를 이용해 윈도우 프로그래밍을 하는데 필요한 모든 것이 정의되어 있습
니다.. 굉장하지요? 그러니 거의 대부분 인클루됩니다...stdio.h가 C에서 그랬듯이요...

그럼 함수가 어떻게 정의되 있는지 한번 보세요...
생소하기 그지 없습니다..
그런데 모르는 함수 몇 개와 너무나 긴 이름들 때문에 복잡해 보일 수도 있습니다..
하지만 계속 공부하다보면..아니 프로그램을 짜다보면.. 이렇게 자세하게 지은 이름들이 얼마나
도움이 되는지 아실 겁니다..

잔소리하나 더 하자면...함수명이나 클래스명이나 변수명을 정할 때는 그 특징또는 기능등을
자세하게 표현할 수 있는 단어를 만드세요..길면길수록 좋습니다..물론 코딩할 때는 짜증나겠지만

는 프로그램이 시작되면 호출되는 함수라고 했지요? 그래서 여러 가지 초기화 루틴
이 들어가는 데요..
C가 하는일이 AFX클래스들을 묶어주는 일이 있었죠?
이 일을 지금 여기서 하는 것이죠.. C를 그대로 사용한다면 우리가 저렇게 해줄 필요가
없었겠죠..아~~물론 저것은 우리가 해야하는 일을 친절한 가 알아서 해준 것입니다.
따라서 가 없다면 우리가 저렇게 일일이 해주어야 합니다..

내용은 이렇습니다..

C라는 클래스의 인스턴스를 생성시키려고 하는데 포인터를 이용하였고..
즉 C 타입의 포인터(int형의 포인터-int *pointer식으로 말이죠..)를 선언하고
도큐먼트 클래스, 프레임윈도우 클래스, 뷰클래스로 각각 우리가 파생시킨(가 알아서
파생시켜준) C, C,C 클래스를 사용하겠다는 것을 포인터인 p를
이용하여 C 클래스에 설정한다음에 (C의 멤버함수)를
호출해서 C클래스와 연결시킨 것입니다..

대충 어떤 내용인지 아시겠죠?
아주 쉽게 얘기해서 AFX클래스로 C, C, C를 사용하겠다 그리고 이를
C클래스와 연결시켜 묶어서 프로그램을 구동시키겠다는 내용이지요..
몇줄 안되는 문장이지만 정말 정말 대단한 일을 하고 있습니다..

우리는 여기서 C클래스와 여기서 파생된 C라는 클래스를 완전히 파헤치자는게 아닙
니다.

개념적으로 어떤 일을 하고, 어디에 위치하고,C라는 클래스를 이용하되 조금 수정또는
추가하여 사용하고자 C라는 파생클래스를 만들었고..이 모양이 대충 어떻게 생겼는지만
알면 됩니다..

거의 2페이지에 걸쳐 설명하였는데..한번 읽어보시고 바로 위의 말슴드린대로 나름대로 정리해
보세요.. 자기 나름대로 정리해 보는 것이 아주 중요합니다.. 처음 개념을 잡는데는 말이죠..

그럼 C와 CView클래스를 보기전에 이들의 기반클래스인 CWnd클래스를 보겠습니다...
갑시다...




Visual C++ 6 강좌(027)



10.AFX(Application Frameworks) (계속5)

2.CWnd

우리가 다음으로 살펴볼 AFX클래스는 C,CView인데..이들의 상당부분의 중요한 기능들이
기반클래스인 CWnd클래스에서 상속받은 것 이기 때문에 이를 먼저 살펴보는 것이 좋을 것 같습
니다..

그럼 위치 확인!!

CObject -> C -> CWnd

CWnd도 모든 클래스의 대부인 CObject에서 파생되었군요...
전에 C도 C이라는 클래스에서 상속받은 파생클래스였는데 CWnd도 마찬가지이군요..

그럼 C은 어떤 내용으로 되어 있을까요?
C에 대해선 MFC시작하기 부분에서 간략하게나마 말씀드렸는데요..
이 클래스는 윈도우 메시지를 다루는(핸들링하는)기능들이 정의되어 있습니다..
그렇다고 우리가 메시지를 핸들링하기위해 이 클래스에서 상속받은 파생클래스를 직접 만들 필요가
있을까요? 사실 프로그래밍을 할 때 그러한 일은 거의 없습니다...

왜일까요?

그 이유는 윈도우 프로그램을 만들 때 기본이 되는 핵심 클래스(Key Class)인 AFX 클래스들,
즉, C,C,CDocument,CView클래스들은 모두 이 클래스에서 상속받은 파생클래스들이기
때문입니다.. 즉 C 모든 AFX클래스들의 기반클래스라는 말이죠...

따라서 모든 AFX클래스들은 C의 메시지 핸들링 기능을 사용할 수 있기 때문에..
메시지 핸들링을 하기위해 C에서 직접 상속받은 파생클래스를 별도로 만들 필요가 없습
니다..

아래에 에 있는 C클래스의 설명부분 중 일부입니다. 참고하세요..
여기에 message-map architecture라는 다소 생소한 말이 나오는데.. 이는 메시지핸들러 함수를 다루는 부분에서 자세하게 설명하겠습니다...

C is the base class for the Microsoft Foundation Class Library message-map architecture. A message map routes commands or messages to the member functions you write to handle them. (A command is a message from a menu item, command button, or accelerator key.)

Key framework classes derived from C include CView, C, CDocument, CWnd, and C. If you intend for a new class to handle messages, derive the class from one of these C-derived classes. You will rarely derive a class from C directly.

참고로 새로운 클래스가 나왔을 때 이에 대한 설명을 에서 보고 싶으시면
워크스페이스의 탭을 클릭하여 다음과 같은 순서로 찾으면 됩니다...

Developer Products -> Visual C++ -> Microsoft Foundation Class Reference
-> Class Library Reference ->

이제 CWnd 클래스에 대해서 자세히 알아볼까요?

CWnd클래스는 크게 두가지 부분으로 나누어 생각해 볼 수 있습니다..


첫 번째 부분
: 윈도우의 크기나 위치, 모양, 상태등을 제어하기위한 기능이 있는 부분


두 번째 부분
: 윈도우에서 발생하는 메시지를 처리하기위한 메시지 핸들러 함수관련 부분

첫번째 부분을 위한 멤버함수는 약 100여개정도가 되구요..두번째 메시지 핸들러 함수라 불리는
맴버함수는 약 200여개가 있습니다..정말 엄청나게 많은 함수지요?

이를 다 보려면 며칠밤은 꼬박 새워야겠군요...큰일났습니다.. 어떻게 하지요?

이제는 눈치들이 빠르셔서 아무리 이렇게 얘기해 봐야 지레 겁먹는 분들은 거의 없는 것 같군요..
먼저 윈도우 크키나 위치, 모양, 상태등을 제어하는 부분은 특별한 경우가 아니면 그대로 사용
하는 경우가 대부분이 이기 때문에 지금으로선 가 만들어 놓은 부분을 그대로 사용해도
전혀 무리가 없습니다..
해봤잖아요...최소화/최대화도 되고 임의크기로 변경도 할 수 있고..이동도 되구요..다 보셨죠..

문제는 메시지 핸들러 함수인데요...200개가 넘는 메시지 핸들러 함수가 윈도우 프로그래밍에서
상당히 중요한..정말 중요한 함수이지만(당연하지요..윈도우가 메시지 구동방식이니..)..지금 당장
그 많은 함수를 다 볼 필요는 전혀 없습니다...자주 발생하는 메시지를 위주로 그에 대응하여
호출되는 메시지 함수를 차근차근 보면 되니까요..메시지 함수도 한 20개 정도의 이름과 내용을
간단하게 머리속에 넣고 있으면 프로그래밍하는데는 별 불편없습니다..
물론..많이 알고 있으면 더 좋게지만요...저는 머리가 나빠서요...

그럼 메시지 핸들러 함수에 대해 살펴 볼까요?

1) 메시지 핸들러 함수(Message Handler function)

메시지 핸들러 함수는 간단하게 메시지를 핸들링하는 함수입니다..
참 웃긴 설명이란 생각이 드는 군요...하지만 이게 정답입니다..

핸들(Handle)이 영어로 '다루다,쓰다,처리하다'라는 뜻이더 군요(동아 프라임 사전)..
그럼 메시지 핸들링이란 것은 '메시지를 다루다', '메시지를 처리하다'란 뜻이 되겠죠?
그러니 메시지 핸들러 함수가 메시지를 핸들링하는 함수라는 얘기입니다..

그런데 이 메시지란 것이 어떤 것이지요? 예...윈도우에서 발생되는 메시지를 말하는 것이지요..
윈도우가 메시지 구동방식으로 돌아간다고 했으니.. 메시지 핸들러 함수를 좀더 자세히 말하자면
윈도우에서 발생하는 메시지를 처리(핸들링)하는 함수라는 말입니다.

어려울 것 하나 없죠? 그럼 윈도우에선 어떠한 메시지가 언제 발생할까요?
메시지가 언제 발생하느냐는 순전히 사용자(user)가 어떤 행동을 하느냐에 따라 달려 있습니다..

사용자가 우두커니 컴퓨터를 보고 있다면 잠시나마 아무 메시지도 발생하지 않지요..
그러나 사용자가 마우스를 잡고 조금만 움직여도 곧바로 마우스가 움직였다는 WM_MOUSEMOVE라는
메시지가 발생하죠..그럼 우리는 프로그램을 짤 때 이 메시지가 발생하였을 때 프로그램이 해야
할 일을 이 WM_MOUSEMOVE함수를 처리하는 메시지 핸들러 함수 함수에다가 해야할 일
을 넣어 주면 되는 겁니다...

그렇다면 함수를 만들었다면 사용즉 호출을 해 줘야 하는데.. 어떻게 하면 되지요?
답은 우리가 더 이상 할 일은 없다는 것입니다.. WM_MOUSEMOVE 메시지가 발생하면 자동적으로
함수가 호출되거든요..그렇게 되 있어요...아주 편리하죠?
프로그래머는 단지 해야 할 일만 메시지 핸들러 함수에 넣어주면 끝나는 것입니다..

또 사용자가 무슨 버튼을 클릭하면 마우스 왼쪽버튼이 클릭되었다는 메시지가 발생하고..
그에 대응하는 메시지 핸들러 함수가 호출될 테니 어떤 버튼이 눌려졌을 때 해야 할 일이 있을 때
이 대응하는 메시지 핸들러 함수에 해야할 일을 넣어 주면 되는 것입니다..

모든게 다 만찬가지예요..아주 아주 쉽습니다.. 적어도 여기까진...그렇죠?

앞에서도 간단히 설명한 것 같은데요..윈도우에서 발생하는 메시지는 전부 WM_어쩌구(대문자)식으
로 되 있습니다.. 그리고 그에 대응하는 메시지 핸들러 함수 이름은 전부 On어쩌구식이 됩니다.

그럼 자주 사용되는 윈도우 메시지가 어떤게 있는지 다음장에서 한번 살펴보죠...




Visual C++ 6 강좌(028)



10.AFX(Application Frameworks) (계속6)

자주 사용되는 윈도우 메시지아 그에 대응하는 메시지 핸들러 함수는 다음과 같습니다..

<표> 자주사용되는 윈도우메시지와 메시지 핸들러 함수

윈도우 메시지
발생상황
메시지핸들러함수

WM_CREATE
윈도우가 생성될(생길) 때


WM_ACTIVATE
윈도우가 (비)활성화 될 때


WM_PAINT
윈도우가 다시 그려져야 할
필요가 있을때


WM_MOUSEMOVE
마우스 움직였을 때


WM_COMMAND
메뉴등으로 명령을 내릴 때


WM_LBUTTONDOWN
마우스 왼쪽버튼 눌렀을 때
OnL

WM_LBUTTONUP
마우스 왼쪽버튼 뗐을 때
OnL

WM_LBUTTONDBLCLK
마우스 왼쪽버튼 더블클릭때
OnL

WM_KEYDOWN
키보드 눌렀을 때


WM_KEYUP
카보드 뗐을 때


WM_SIZE
윈도우 크기가 변경됬을 때


WM_MOVE
윈도우가 이동되었을 때


WM_TIMER
설정된 타이머 시간이 다 되
을 때


WM_DESTORY
윈도우가 없어질 때






보신 소감이 어떻습니까? 너무어려워서 죽겠지요?

이름만 봐도 이 메시지가 언제 발생되는 메시지인지 금방 알 수 있습니다..다른 메시지들도
마찮가지예요..그러니 어려울 것 하나 없습니다...

유심히 보신 분들은 WM_COMMAND 즉, 메뉴같은 것을 클릭했을 때 발생하는 메시지에 대응하는
메시지 핸들러 함수가 없네요...
WM_COMMAND 메시지는 조금 다른 방법으로 처리하는데요..그 이유가 있습니다..
메뉴와 같은 것들은 프로그래머가 직접 만든 것이지요? 물론 우리와 같은 경우에는 가
만든 것이 전부지만요..어쨌든 프로그래머가 직접 만든 것입니다..

프로그래머가 어떤 메뉴항목을 만들지는 아무도 모릅니다..정말 며느~도 모르지요..
그러니 어떻게 각각의 메뉴항목에 대한 메시지를 미리 정해 놀 수 있겠습니까?..
그래서 이런 것을 일과적으로 처리하는 WM_COMMAND라는 메시지를 둔 것이지요.. 이것만으로도
우리는 프로그램을 작성할 때 상당한 도움을 받습니다..

WM_COMMAND 메시지는 메시지가 발생할 때 어떤 항목이 클릭되어 발생했는지에 대한 정보를 가지고
있지요.. 그래서 메뉴항목의 ID를 참조하여 메뉴항목의 어떤 메뉴가 클릭되었다고 하는 추가정보를
같이 보내오기 때문에 우리는 WM_COMMAND메시지가 발생하였을 때 추가정보를 보고 이에 대응하는
함수를 연결시켜 주고 이 함수에 해야 할 일을 넣어 주면 됩니다..

다른 메시지 함들러 함수들보다는 조금 복잡한 것 같군요..그럴 수도 있지만요.. 직접해보면..
정말 별거 아니지요..

여러분이 위의 설명을 보면서 가장 걱정되는 부분이 어떻게 WM_COMMAND라는 메시지가 발생하였을
때 그 추가정보(메뉴ID같은거)를 보고 우리가 직접만든 함수와 연결시켜고 이를 어떻게 호출해야
되는지에 대한 부분일 것입니다.

하지만 걱정할 필요는 하나도 없습니다.. 이와 같은 일을 Class Wizard(앞으로 클래스위저드)가
아주 간편하게 해주거든요..우리는 각 메뉴마다 ID를 만들어 놓고 클래스위저드를 이용하여
이에 대응하는 함수를 만들어주면 되거든요..그러면 그 메뉴항목이 선택되면 WM_COMMAND 메시지가
가 발생하고 이에 대응하는 함수(우리가 직접만든 함수)가 자동으로 호출됩니다..
끝내주죠?

그러면 클래스위저드를 사용하는 방법만 알고..이에 익숙해 지기만 하면 되겠군요..
클래스 위저드의 사용방법은 AFX강좌가 끝나고 우리의 첫 번째 프로그램을 만들면서 자세하게
알려드리겠습니다.. 먼저 말씀드리지만 사용하기가 편리하기 그지 없으니 전혀 걱정하지 마세요..


윈도우 메시지(WM_~~)가 발생하면 자동으로 이에 대응하는 메시지핸들러 함수가 호출된다고 하였
는데..어떻게 자동으로 호출될 수 있을까요? 궁금하지 않으세요?

사실 모르셔도 지금으로선 상관없을지도 모릅니다..
그래도 메시지 핸들러 함수를 앞으로 수도없이 정말 지겹게 사용하게 되는데..그때 마다 이런
궁금증을 품고 있다면 정신건강에 해로울 수 있으니..간단하게 설명드리겠습니다...


2) 메시지 핸들러 함수의 호출원리

제목이 거창하군요...하지만 그 원리란게 워낙 간단해서 설명드리기가 민망하기 그지없습니다..

윈도우가 메시지를 발생하면 이런이런 메시지가 발생하였다고 프로그램에게 알릴텐데..
이 메시지라는게 시도때도 없이 수도없이 발생하는 것이거든요.. 귀찮기 그지없지요..
프로그램도 뭔가 해야 할 일이 있는데..하고 있는 도중에 이런 메시지가 계속 나오면 그때마다..
즉시 그 메시지에 대한 메시지 핸들러 함수를 호출할 수 있을 까요?

그래서 모든 윈도우 프로그램은 이 메시지들을 일단 저장해 놓을 수 있는 일종의 메모리 공간을
가지고 있는데요..그걸 메시지 큐라고 부릅니다..

그래서 첫 번째 들어온 메시지를 첫큐, 두 번째 들어온 메시지를 두 번째 큐라고 하고 이 메시지
가 발생하는 간격이 길면 '큐거리가 길다'라고 하구요 간격이 짧으면 '큐거리가 짧다'고 합니다.
그리고 큐거리가 지나치게 길거나 짧으면 메시지를 처리하기 곤란하니 적당한 큐거리를 가지는
습관을 가져야 합니다...
그리고 들어온 모든 메시지를 한번에 처리하면 '한큐에 끝냈다' 또는 '스킬'이라고 하고...
이럴땐 아무말 하지 말고 종료버튼을 누르고 유유히 손을 씻고 밖으로 나오면 아주 멋지죠..
절대도 아무말도 하지 않아야 합니다.. 그래야 멋있다니까요...
죄송합니다.. 너무 지나쳤습니다..여러분의 귀한 시간을 뺐었습니다.. 용서하십시오...

다시 제정신을 차리고...

발생하는 메시지를 일단 저장해 놓는 메모리 공간을 메시지 큐라 하였죠?

혹시 자료구조를 보신분들은 아시겠지만..자료구조에는 스택,큐,데크,리스트등 여러 가지가 있습
니다..그래서 FIFO(먼저 들어간 놈이 먼저나온다),FILO(먼저들어간 놈이 나중에 나온다)등의
말이 나오는데요.. 스택(Stack)이 FILO에 해당하구요.. 큐(Que)는 FIFO에 해당합니다..
이런 것은 아직 알 필요가 없지만 혹시나 다른 책에서 이런 설명이 없어서 조금이나마 궁금해하신
분들을 위해 그냥 말씀 드린 것입니다..

어쨌든 이 메시지큐라는 것에 메시지가 저장되어 있다가 하나씩 하나씩 그에 대응하는 함수가
호출 되어지는 것입니다...

이 윈도우 메시지라는 것은 나중에 메시지 구조부분에서 정확하게 설명드리겠지만.. 단순히
WM_~식의 메시지 이름만 전달되는 것은 아닙니다...
예를 들어 마우스를 클릭하였다면.. 그때 커서위치가 어디였는지등의 추가정보가 같이 전달
됩니다.. 그러니 메시지 큐에는 이러한 내용들이 전부 들어 있겠죠..

메시지 핸들러 함수도 이러한 추가정보들을 처리하게 됩니다...

그럼 이 메시지큐에 있는 메시지를 어떻게 메시지 핸들러 함수와 연결시키는지 볼까요?




Visual C++ 6 강좌(029)



10.AFX(Application Frameworks) (계속7)

메시지와 메시지 핸들러 함수를 연결시킨다는 얘기는 이런 이런 메시지가 발생되었을 때
이런 이런 메시지 핸들러 함수를 호출시키는 루틴을 말하는 것이지요...

이는 switch,case문으로 쉽게 구현할 수 있습니다..

{
while(msg != WM_QUIT){

switch(msg){

case WM_CREAT:
(); break;
case WM_PAINT:
(); break;

....

}
}

뭐 이런식으로 하면 되지요.. 간단하지요? 여러분이 C의 기본문법정도는 알고 있다면, 이같은
문장은 쉽게 알 수 있습니다..그래도 간단히 설명하겠습니다..

while문으로 무한루프를 만들었군요.. 그야 당연한게 메시지란 놈은 프로그램이 시작해서 끝날 때
까지 계속 발생하는 것이니까요.. 프로그램의 종료를 의미하는 WM_QUIT메시지가 발생할 때 까지
아래의 switch, case 문을 계속적으로 실행한다는 말이군요..
msg라는 변수가 메시지의 이름을 받는데요.. 그 이름에 따라 실행되는 루틴이 달라지죠..
그래서 메시지가 WM_CREAT일 경우일 땐(즉, msg == WM_CREAT) ()함수를 호출하게 하였습
니다..이런식으로 모든 메시지에 대해 정의해 주면 프로그램실행동안 발생하는 모든 메시지에
대해 이를 처리하는 메시지 핸들러가 자동적으로 호출되겠지요...


이것을 우리가 해줘야 할까요? 벌써 다 되있으니 할 필요가 없습니다.. 우린 그저 그저..
어떤 메시지를 호출 하는 핸들러 함수가 뭔지만 알면 되고 그 안
 
 
 
####################중간은 어디 갔을까?############엥..
 
 
 
 
 
 
 
Visual C++ 6 강좌(032)



10.AFX(Application Frameworks) (계속10)

3.C

앞에서 CWnd가 C와 CView클래스의 기반클래스라는 얘기를 하였지요?

그렇다면 C나 CView는 CWnd가 가지고 있는 기능을 다 가질 수 있겠군요...
물론 메시지 핸들러 함수를 사용한다면..파생클래스이니 메시지 맵을 사용하여 오버라이딩
했을테지요..실제로 보면 그렇게 되 있습니다...

어쨌든.. 다 알고 있다 하여도 다시한번 위치확인!!

CObject->C->CWnd->C

이젠 설명하지 않아도 다 아시겠지요.. 이 말이 무슨 의미 인지를...

그럼 이 클래스는 어떤 객체를 표현한거였지요? 예~~눈에 보이는 영역인 윈도우틀을 클래스로
구현한 것이 C지요? 이 설명은 너무 오래전에 해서..말씀드리기가 쑥스럽군요..

그렇다면 어떤일을 하겠습니까?
물론 윈도우틀과 관련된 모든 일을 수행합니다..
클라이언트 영역을 View로 덮어주는 일도 하구요..

메뉴와 툴바 상태바 같은 것도 생성시켜준다고요?
대단하시네요..물론 메뉴나 툴바, 상태바 같은 것은 대부분의 프레임윈도우가 수행하는 일이긴
하지만 프로그램에 따라서 달기도 하고 달지 않기도 하지 않나요?
그래서 이것을 위한 기능을 구현되어 있지 않고요..이러한 것들을 쉽게 달 수 있도록
하는 기능만을 가지고 있습니다..

그럼 툴바나,메뉴,상태바등을 프레임윈도우에 달려면 어떻게 하면 되겠습니까?

어허~~의견이 너무 제각각이군요..

앞으로 이와 유사한 질문을 제가 던지면 머리속에선 "어떻게"가 생각나면 안되고 "언제"가
먼저 생각나야 합니다..

왜냐하면 프로그램중에 언제 이러한 기능을 수행해야 할까를 생각하면 어디에다가 이 기능을
넣어야 하는지가 결정됩니다..앞에서 수도없이 말씀드렸잖아요...

그리고 나서야 비로서 "어떻게"게 나와야 합니다..

즉 "언제"->"어디에"->"어떻게"식으로 생각을 하시라는 얘깁니다...

그럼 이런식으로 생각해 봅시다...
언제 메뉴나 툴바나 상태바가 생기도록 하면 될까요? 프로그램 종료하기 직전에요?
프로그램 시작하자마자요? 아님 아무때나 꼴리는데로 하면 될까요?

예~~예~~슬슬 정답이 나오는군요...우리가 프로그램을 실행시키면 윈도우틀이(프레임윈도우)가
생기고 메뉴나 툴바등이 생기고 클라이언트영역이 허였게 되고(물론 아닌 것도 있고요)됩니다.
툴바나 메뉴등은 메인프레임에 다는 것이니까 윈도우가 생성될 때 달면 됩니다...

그럼 "언제"는 해결됐으니..."어디에" 이런 기능을 넣으면 되는지를 볼까요?

자주 쓰이는 메시지와 메시지 핸들러 함수를 표를 보셔서 아시겠지만..윈도우가 생성될 때
무슨 메시지가 발생한다고 하였죠? 예~~ WM_CREAT라는 메시지가 발생하죠?
그럼 이 메시지가 발생할 때 자동적으로 호출된느 메시지 핸들러 함수는 이지요?
그렇다면 답은 나왔네요..윈도우가 생성될 때 이런 메뉴나 툴바를 생성시켜야 하니까..
윈도우가 생성될 때 발생하는 메시지를 핸들링해주는 메시지 핸들러 함수 안에
메뉴나 툴바등을 생성시키는 루틴을 넣어 주면 되겠군요..

이제 "어디에"까지 해결됩습니다..

그런 다음에는 진짜 프로그래밍 실력발휘를 해야 하지요... 하지만 지금은 아니예요..
지금은 메뉴나 툴바를 생성시키는 시간이 아니거든요...

어쨌든 워크스페이스에서 ()함수를 찾아 클릭해 보세요...
C클래스를 찾아봐야 그런 클래스는 안보입니다...당연하지요..그건 MFC 이고..우리는
를 이용해서 이 클래스에서 상속받아 파생클래스를 이용하지요..
그 이름은? 예~~C입니다..이 항목을 클릭하시면..가 보이시죠?
그럼 어떻게 정의되어 있는지 한번 보세요...
보셨습니까? 뭐라고 알 수 없는 내용이 잔뜩있지요?

지금 자세히 살필 필요는 전혀 없지만 무슨 내용인지만 알고 넘어가자면
툴바클래스의 멤버함수인 Create라는 함수를 이용해서 툴바를 생성하였고..
상태바의 클래스의 멤버함수인 Create를 호출해서 상태바를 생성하였습니다.
마지막 부분에는 툴바가 도킹(메인프레임에 붙어있는 것)할 수 있도록 여러 가지 내용을 넣었군요
아무리 생각해봐도 정말 고마운 입니다..

친절하게도 이렇게 만들어 줬기 때문에 우리가 이를 컴파일해서 실행파일을 만들어 실행하면..
윈도우프레임에 툴바와 상태바등이 있는 거지요...

사실 이정도만 알고 있어도 상관은 없습니다.. C란 클래스는 다른 AFX클래스와 마찮가지로
처음부터 끝까지 여러분이 MFC Programming을 하는한 계속 나옵니다.. 벌써부터 힘빼지 맙시다..

지금은 그저 에게 감사의 마음만 가지고 있으면 됩니다..우리의 학습량을 어찌됐건..
줄여줬으니 까요...

마지막으로 워크스페이스를 다시한번 봅시다..C를 보고 그안에 어떤 멤버와 어떤 함수들이
있는지 살펴보십시오..그냥 눈인사 정도만 하세요..벌써부터 친해지려 하지 마시구요...
C클래스의 선언부분은 어떤 해더파일에 있지요? .h이지요?
그리고 클래스 정의부분은 .cpp에 있습니다..

그냥 눈요기로 대충 봐두세요...



Visual C++ 6 강좌(033)



10.AFX(Application Frameworks) (계속10)

4.CView

CView클래스도 CWnd클래스에서 상속받은 파생클래스입니다..그러니 메시지 핸들러 함수라든지
윈도우 자체를 제어하는 기능들을 다 포함하고 있는 셈이죠...

이 일반적인 원도우로서의 역할에다가 뷰윈도우로서의 고유한 역할을 추가한 것이 CView클래스
입니다..

벌써 설명을 다 했듯이 데이터를 여러 가지 방법으로 보여주는 역할을 하지요..
그리고 C나 C같은 클래스는 거의 대부분의 윈도우 응용프로그램들이 비슷비슷하게
가지고 있는 부분이지만 데이터를 처리하고 보여주는 등의 일을 하는 CView와 CDocument는
프로그램들마다 다르기 때문에 우리의 프로그래밍 실력은 여기서 판가름이 난다고 할 수 있죠..

C는 일관된 유저인터페이스와 관련이 깊기 때문에 다른 여타 프로그램들과 크게 다를
바가 없지만요 실제 우리가 이러이러한 기능을 하는 프로그램을 만든다 하면 그건 다른 프로그램
들과 다를 테니까 거의 대부분이 이 CView클래스와 CDocument클래스에 다가 이러한 내용을
넣어주기 때문에 실제 우리가 가장 많이 다루게 되고 가장 잘 알고 있어야 하는 부분입니다..

전에 설명했던 얘기를 간단히 요약해서 말씀드리자면,

우리가 이러이러한 기능을 하는 프로그램을 만든다고 하면 그러한 기능은 거의 CDocument에
넣게 되는데요..그 이유야 이 클래스가 데이터를 처리하고 저장하는 등의 일을 하기 때문이죠..

그런데..같은 데이터를 처리하였다 하더라도 이 데이터를 보여주는 방법은 정말 엄청나게 많거
든요?

예를 들어 우리가 증권투자를 도울 수 있는 주가분석프로그램을 만든다고 합시다..
그러면 주가와 관련된 데이터를 이러저러하게 처리하여 저장해야 되겠죠? 이렇게 해놓고..
이 처리된 결과를 뷰윈도우(클라이언트영역)에 보여줘야 하는데요..
만약 우리가 상장회사의 금일 주가변동을 시간대별로 보여줘야 한다면 어떻게 하면 될까요?

뭐 표를 만들어 가로축은 시간의 흐름을 세로축에는 상장회사별로 숫자로 보여 줄 수 도 있고요..
단순한 막대그래프 형태로 보여줄 수 있고요..아니면 곡선으로 보여줄 수 도 있고요..
고요...고요...고요...고요...정말 방법은 많겠죠?

데이터를 처리하고 저장하는 도큐먼트부분은 하나라도 보여주는 뷰부분은 여러개가 될 수 있겠죠?
그래서 뷰윈도우는 어찌됐던간에 어떤 도큐먼트와 연결되어있어야 합니다..

그렇지 않으면 이 뷰윈도가 어떤 도큐먼트에서 처리된 데이터를 보여주는 지 알길이 없으니까요..

그리고 도큐먼트의 입장에서 보면 하나의 도큐먼트가 여러개의 뷰를 가질 수 있는 셈이지요..

사실 지금으로선 이정도의 설명으로 CView클래스의 대한 설명은 끝입니다..

그러면 가 CView클래스에서 상속받아 만들어준 파생클래스 C를 한번보지요..

CView클래스가 선언된 부분이 저장되어 있는 헤더파일(.h)를 한번볼까요?
어떻게 선언되 있는지 보게요...어떻게 찾지요? 예 워크스페이스의 탭을 클릭해서
거기에 있는 Header Files 라는 폴더를 클릭해 주면 모든 헤더파일이 다 사이좋게 모여있죠?
거기에서 .h를 클릭하면 되죠..

지금까지 계속 이런식으로 파일을 찾았는데요.. 더 간단한 방법이 있습니다..
우리가 실제로 프로그램을 짤 때는 탭에 놓고 작업을 하는데요...
거기서 어떤 클래스의 헤더파일이나 소스파일을 보고 싶을 때 지금까지 한 방법으로 탭
으로 이동해서 찾아도 되지만요.좀 성가시죠...
더 쉽게 보려면 그냥 탭상에서 클래스 이름을 더블클릭하면 그 클래스가 선언되어 있는
헤더파일을 보여줍니다.. 간단하죠..
그리고 그 클래스의 어떤 멤버함수를 클릭하면 그 멤버함수가 정의되어 있는 부분을 보여주는데..
그 보여주는 부분은 곧 그 클래스의 멤버함수가 정의되어 있는 소스파일(cpp)중에 우리가 클릭한
멤버함수의 정의부분이 되는 셈이죠...

그럼 한번 의 C클래스를 더블클릭해 보세요... 좀전에 C에서 우리가
찾아서 클릭한 .h의 내용이 똑같이 나오죠...편리하군요...

그럼 진짜로 한번 훑어 보세요...

뭔소리를 하는건지...우리는 여기서 두가지 멤버함수만 기억해 두면 그걸로 족합니다..

뷰가 하는 역할이라는게..도큐먼트에서 처리되어 저장되어 있는 데이터를 가져다가 화면에 보여
주는거잖아요..그게 거의 전부죠..

그러면 앞에서 설명하였다시피...그렇다면 어떤 도큐먼트의 내용을 보여주자면..두 개의 두분으로
나뉘어 지겠군요..어떤 도큐먼트의 내용을 보여주는건지 일단 알아야 보여주던지 말던지..할테니
도큐먼트에 저장된 데이터를 가져오기 위해선 도큐먼트를 얻어와야 해야겠죠.. 그리고 얻어왔다면
보여주면 되는거죠..
그런데 보여주는 기능은 크게 두가지로 나눌 수 있습니다.. 너무나 당연한 얘기지만..
화면에 즉 모니터를 통해 직접 보여 줄 수도 있고...프린터를 해서 보여줄 수도 있잖아요?
그래서 화면에 보여주는 기능과 프린터 기능이 있겠지요..
그리고 어떤 내용을 어떻게 보여주느냐하는 문제는 순전히 프로그래머 맘데로입니다.
너무나 당연한 얘기지요..
이런이런 내용을 이렇게 보여주라는 법은 없으니까요...이 부분에서 여러분의 아이디어와
프로그래밍 실력이 결합해서 정말 쥑이는 프로그램이 나올 수 있는 거죠...

또 기름끼 좌악 빼서 보면 다음과 같이 되어 있습니다...

Class C: public CView
{
public:
C* ();
Virtual void (CDC* pDC);
protected;
virtual BOOL (C* pInfo);
virtual void (CDC* pDC, C* pInfo);
virtual void (CDC* pDC, C* pInfo);
};

정말 기름끼 쫙 빼군요...

맨위의 문장은 C가 AFX클래스인 CView에서 public으로 상속받은 파생클래스라는 얘기구요..
다 아시죠?
그 다음 public로 선언되어 있는 함수들은 외부사용이 가능한 멤버함수라는 말이구요..
그 아래 protected로 선언되어 있는 함수들은 이 클래스의 내부적으로나 파생클래스 즉, 우리가
만든(사실은 가 만들어준) C를 상속받을 파생클래스(현재로선 없지요..)내부에서
사용가능하지만 외부사용은 안된다는 의미이지요..

위에서 설명했던 도큐먼트를 얻어오는 역할을 함수가 있군요...
선언된 모양을 보니 도큐먼트의 더정확히 말하면 도큐먼트 클래스의 포인터를 얻어오는군요..
즉 C이라는 클래스형의 포인터를 반환한다는 말이죠.. 우리는 이 포인터를 가지고 도큐먼트의
데이터를 이렇게 보여줄 수 있습니다..

그리고 실제로 보여주는 기능을 함수인 라는 멤버함수가 보입니다..
실제 이 멤버함수가 CView클래스의 대부분의 역할을 담당한다고 볼 수 있습니다..
우리는 이 함수안에다 실제로 보여주는 기능을 넣어 주면 되는 거죠..
이렇게 다 만들어져 있으니 정말 편리하기 그지 없습니다..

어떻게 정의되어 있는지 볼까요..
워크스페이스에 C클래스를 보면 함수가 있지요?
클릭해 보세요.. 어떻게 되어 있습니까?

C::(CDC* pDC)
{
C* pDoc = ();
ASSERT_VALID(pDoc);

file://TODO: add draw code for native data here
}
음~~역시 예상한데로 별내용 없군요..
일단 를 호출했군요..
C형으로 선언된 pDoc이라는 포인터에 가 반환하는 현재 도큐먼트의 포인터를
저장하죠.. 그럼 우리는 이 pDoc이라는 포인터를 이용하여 도큐먼트의 저장된 데이터를 참조
할 수 있는겁니다..
주석문에 file://TODO라는 부분에다가 우린 실제로 어떤 데이터를 어떻게 보여주는지를 넣어주어야
겠지요..이걸로 끝~~~


클래스 선언부분으로 돌아와서 함수밑에 보니 On어쩌구Printing이라는 함수가 세 개
있군요...Printing이라는 말을 보니 프린터 출력과 관계된 함수인거 같죠?
이 프린터를 출력하는 부분은 뒤에서 설명하도록 하구요...

우리가 CView라는 클래스를 보면서 기억해야 할 부분은 3가지 정도입니다..
이것만 기억해 주고 넘어가면 되는 거죠..


CView는 CWnd에서 파생되었으므로 윈도우자체를 제어하고 메시지 핸들러 함수를 이용할 수
있다.

CView함수의 고유한 부분은 도큐먼트를 얻어 그 내용을 보여주는 것이다..

보여주는 기능은 실제로 함수에 구현하고 특별히 프린터로 출력하는 부분은 프린터
관련함수를 이용하여 보여 준다..

이것으로 CView클래스의 내용은 마치구요.. 다음은 CDocument클래슬 살펴보죠...



Visual C++ 6 강좌(034)



10.AFX(Application Frameworks) (계속12)

5.CDocument

이제 AFX클래스의 마지막인 CDocument클래스를 살펴보도록 하겠습니다..

CDocument클래스는 CView클래스와 함께 우리의 프로그래밍 실력을 마음껏 발휘하는 곳이죠..
특히 CDocument는 실제 데이터를 처리 저장하는 기능을 하기 때문에 우리가 이러이러한 일을 하는
프로그램을 만들겠다고 마음먹었다면 이러이러한 일이라는 것이 전부 CDocument가 해야 하는 일
이 됩니다..가 CDocument클래스의 파생클래스인 C이라는 클래스를 만들어 놓았지만..
안에보면 별내용이 없기 때문에 우리가 실제로 다 해줘야 하지요..

CDocument는 MFC 계층도에서 다음과 같은 위치에 있습니다...

CObject -> C -> CDocument

CView와 C가 C에서 상속받은 CWnd의 파생클래스임에 반에 CDocument는 C
에서 직접 상속받았군요...

그러니 현재로선 CWnd의 멤버함수는 자유롭게 사용할 수 없습니다...

뭐 어쨌든 간에 중요한 건 이런거죠...

CDocument라는 클래스는 눈에보이지는 않지만 실제 프로그램이 하는 기능을 하는 정의하는 곳입니다
MFC에 CDocument클래스에는 다음과 같은 내용이 정의되어 있습니다.


파일로부터 데이터를 읽어오는/저장하는 기능

새로운 데이터를 만드는 기능

데이터가 변경된 사실을 뷰(객체)에 알 리는 기능

대충 이런 기능을 가지고 있지요.. 그러니 우리가 만든(실제 가 상속받아 만들어준) 클래스
인 C도 위와 같은 내용을 가지고 있지요..

파일로부터 데이터를 읽거나 저장하는 기능이란 파일메뉴 같은데 보면 '열기','저장'이라는 서브메뉴
가 하는 기능을 말하죠...

우리가 윈95용 프로그램에서 파일열기나 저장하기를 클릭하면 다이얼로그 박스가 나오는데요..
그 생김새가 다 똑같죠? 이건 일관된 인터페이스와 관련이 깊은 것인데요...
일반적으로 윈도우 응용프로그램들은 파일열기, 저장하기, 글(폰트나 폰트사이즈,색깔등등),색깔
선택(미리정의된 색깔이나 사용자 정의 색을 선택)등의 기능을 하는 대화상자(Dialog box)가
거의 똑같습니다..

MFC도 위와 같은 공통된 대화상자를 제공하거든요...그냥 갖다가 조금만 수정해서 사용하면 되는
거죠...이런걸 흔히 공통 다이얼로그 박스라고 합니다....

파일 열기,저장 얘기하다가 조금 얘기가 삐져나왔는데요..

어쨌든 지금으로썬 CDocument를 이해한다는 것은 별 의미가 없구요..
단지 CDocument에 우리가 실제로 프로그램이 이러이러한 기능을 수행할 수 있도록 그 기능을 넣어
주어야 한다는 것과 실제 우리가 프로그래밍을 할 때 제일 중요시 여겨야 한다는 거죠..

보통의 비주얼 C++책을 보면 인터페이스(뷰만해도 리스트뷰,트리뷰등, 각종 컨트롤 뭐~ 버튼,스핀버튼
어쩌구 저쩌구..분할윈도우..어쩌구 저쩌구..)에 너무 많은 내용을 두고 설명을 하는데요..
사실 프로그램을 짜다 보면 이런 인터페이스는 일부만 사용하게 됩니다..
물론 엄청나게 큰 프로그램을 만든다고 치면 전부 사용할 지도 모르지만 그런 프로그램을 어느누가
혼자서 만들겠습니까?

제가 말씀드리고 싶은 것은 이런 것에 너무치중해서 공부하다보면..공부를 다하고 나서도 아무 프로
그램도 만들지 못한다는 거죠...

인터페이스란 것은 사용자들이 쉽게 능률적으로 프로그램을 사용할 수 있도록 도와 주는 것에 불과
하구요..실제 프로그램에서 중요한건 그 프로그램이 어떤 일을 어떻게 하느냐입니다..

이 어떤 일을 어떻게 하느냐는 CDocument클래스와 관련이 깊지요...완전히 객체지향적인 프로그램을
만든다면요...

물론 인터페이스가 중요한건 사실이고..요즘 프로그램은 인터페이스에서 판가름이 나는 경우도 비일
비재합니다.. 엄청나게 중요한 인터페이스라 할지라도 프로그래밍을 공부하는 초급.중급자들에게는
인터페이스보단 프로그램의 기능쪽에 더 많은 관심을 가지라는 말씀입니다..

예를 들어 우리가 초고속 검색 DB를 만들겠다고 마음먹었다고 합시다..

검색DB의 인터페이스란게..너무 뻔한거 아닙니까? 이런저런 단어를 입력하면 그 단어와 관련된
데이터를 보여주죠.. 이런 프로그램에서 혁신적인 인터페이스란게 어디있겠습니까?
그런걸 만든다면 여러분은 돈방석에 앉으실 준비를 해야죠...
"머리속으로 단어를 생각하면서 프로그램을 째려보면 그와 관련된 데이터가 나온다"
모르긴 몰라도 뭐 이정도 인터페이스는 되야 될겁니다..

실제 이런 프로그램에선 어떤 것이 중요하겠습니까? 검색엔진!! 이 검색엔진을 어떻게 만드느냐죠..
실제 DB는 어떠한 자료구조를 가지고 효율적으로 저장되며 검색되어지는가..어떠한 방식으로 검색
하는가..검색속도를 얼마만큼 개선시킬 수 있는가..즉 응답시간(리스폰스 타임-response time)을
얼마나 줄일 수 있는가? 입력된 단어와 데이터의 연관성은 어떠한 식으로 결정하는가? 등등
실제로 중요한 질문이 엄청나게 많습니다...

이런 곳에 더 많은 관심을 가지셔야 한다는 말이죠...상대적으로 쉬운 언어들이 엄청나게 많습니다.
흔히들 4GL(4세대 언어)라고 하는 언어들이죠.. 뭐 델파이니..영~~파이니(경상도 사투리)하는거
말입니다.. 이런 언어들은 어떻게 보면 결정적인 한계를 가지고 있습니다...델파이로 DB를 개발한다고
하면 흔히 델파이에서 제공되는 검색 알고리즘을 사용합니다..ACCESS같은 거도 마찮가지구요..
그럼 DB를 만드는 것은 쉬울 수 있지만..뭔가 혁신적인 검색엔진을 가진 DB는 가질 수 없게 되죠..
한마디로 그놈이 다 그놈이라는 말이죠...아주 지나치게 심하게 얘기해서 말이죠...

제가 말씀드리고자 하는 내용은 뭐 C++가 최고다.. 델파이는 영~~파이다 라는 얘기가 아닙니다..
델파이를 쓰는 사람이 얼마나 많다고요...델파이는 VC++이 가지지 못한 수많은 장점들을 가지고 있
습니다..

여러분이 C언어 프로그래머가 되고자 하신다면...C언어의 특징을 이해 하신 셈이죠...
그 많은 언어중에 C를 선택하셨으니까요...

그 특징을 보건데...C언어는 요즘같이 일관된 인터페이스의 프로그램을 만드는 세상에서 인터페이스
설계조차 다른 언어들에 비해 그리 편한 것만은 아니라는 거죠..
실제 ACCESS로 DB를 만든다고 하면 버튼 하나를 만들어 이것이 하는 일을 정의하는 과정이 VC++보다는
훨씬 간단합니다.. 그럼에도 불구하고 여러분이 C++을 하는 이유는 그런 4GL로 만든 DB보다 더 강력
한 DB를 만들 수 있기 때문이죠...

저도 이 강좌를 앞으로 진행하면서 인터페이스와 관련된 내용은 그렇게 심도있게 하지 않을 것입니다.
이런 인터페이스는 프로그램을 만들면서 필요해 질 때 봐도 된다는 거죠..

컨트롤 중에 진행컨트롤이라는 것이 있는데요.. 우리가 파일같은거 복사할 때나 프로그램 로딩할 때
흔히 나오는 거죠..통신에서 다운로드받을 때도 흔히 볼 수 있는거죠..지금 어디까지 다운을 받았다
하는 것을 비쥬얼하게 보여주는 컨트롤인데요...

지금 그런걸 우리가 X빠지게 배워서 뭐 어쩌겠다는 겁니까?

그런걸 배우는 시간에 파일을 어떻게 저장하고 어떻게 읽으며 이러이러한 데이터를 어떻게 처리해야
하는 지를 배우는게 남는거라는 거죠...

그런다음에 해도 전혀, 네버, 절대로 늦지 않는다는 얘기죠..

CDocument는 완전히 잔소리만 하다가 볼일 다 봤습니다..

실제로 볼 내용도 없어요.. 실제 우리가 프로그램을 짜면서 보고 느껴야 하는 거죠...

한가지만 기억하고 넘어갑시다..CView에서 처리된 데이터를 보여주죠?
보여줄 데이터를 처리하는 일을 하는 객체가 도큐먼트구요..이 도큐먼트를 클래스로 구현한 것이
CDocument라는 거죠...

이것으로 AFX(C,C,CView,CDocument)설명을 마치도록 하겠습니다..
별로 한 것도 없이 뭔갈 마친다고 하니까 좀 쑥스럽군요...

다음으론 우리의 첫 번째 프로그램 을 만들어 보도록 하겠습니다..

실제 우리가 배운 AFX클래스와 간단한 그래픽관련 클래스와 멤버함수를 이용하여 만들 예제 프로그램
입니다..

지금까지 한번도 VC++을 직접 해보지 않으신 분들은 다음장에서 설명하는 예제는 꼭 따라서 해주시길
바랍니다..직접 해보지 않고 생각치 않으면 아무짝에도 쓸모없는 설명이 되 버리니까요..



Visual C++ 6 강좌(035)



11.AFX 예제 프로그램 - .exe


드디어 프로그램이라는 걸 만들어 보는군요.. 그것도 Visual C++로 말이죠...

실제로 프로그램을 개발하는 것 처럼 설명을 진행해 나가도록 하겠습니다...

우리는 지금 이런 프로그램을 개발하려고 합니다..

우리가 클라이언트 영역에 클릭을 하면 조그만한 사각형이 그려집니다..
거의 점만한 사각형으로 우리는 그림을 그릴 수 있습니다.. 물론 아주 불편하게 말이죠...
또한 그림을 확대에서 그릴 수도 있게 끔 할 겁니다....

이정도도 대단하죠?

그럼 프로그램 설계를 해보죠..

기능부터 정의를 할까요? 만들 프로그램에 대해서 설명하면서 다 해 버리긴 했지만..실제 프로그램을
만든다는 가정하에 해봅시다..


사용자가 마우스를 클라이언트 영역에서 클릭을 하면 조그만한 사각형을 표시해 준다..

사용자가 크기를 변경시키면 그 크기대로 그림을 그린다...

끝이죠? 이만하면 됬습니다..
복잡한 프로그램은 그 기능을 명확히 정의하는게 그리 간단하지 않습니다..
프로그램의 기능을 명확하게 정의해 놓으면 프로그램을 실제 짤 때 상당히 도움을 받습니다..

그럼 프로그램의 기능을 정의했으니 그다음은 어떻게 하죠?
객체지향적 프로그램을 만들거니까..프로그램을 몇 개의 객체로 나누는 세분화 작업을 해야죠?
우리가 MFC를 이용하여 프로그램을 만들거니까...MS사가 권장하는 방법을 그대로 사용하면 되겠군요..

일단 메인프레임 윈도우, 뷰, 도큐먼트, 프로그램을 구동시키는 객체 4개의 객체로 나누면 되겠군요..

그럼 각 객체마다 하는 역할을 분담시켜야겠죠? 이게 바로 객체지향적 프로그래밍이니까요..

그럼 이 4개의 객체를 일단 일렬로 세우고...차렷..열중셔..앞으로 나란히...

그럼 맨앞에 메인프레임 너는 사용자의 명령을 받는 특히, 그림확대, 이동의 명령을 받는 기능을
해라 알았나? 예~~(메인프레임 대답)

그다음 뷰! 앞으로 나왓!
너는 사용자가 네 위에다 마우스로 클릭을 하면 죄그만한 사각형을 그리도록 알았나?
예~~(뷰 대답..잽싸게 들어가는 뷰~) 야야야~~너...왜그러시는데요?(어눌한 뷰)...끝까지 들어야지
메인프레임 윈도우가 너한테 어떤 일을 시키면 시키는 데로 해라.. 알았나? 예~~~

다음!~~~ 옛!(잽싸고 똑똑한 도큐먼트)
넌 뭘해야지? ~~~~~ 전 아직 할거 없습니다!!(당당한 도큐먼트)...
넌 버전업할 때까지 대기하도록!! 옛!(땡잡은 도큐먼트)


또 장난좀 쳤습니다...저도 가끔은 이래야 쓸맛이 나거든요...이해해 주세요..
위의 얘기를 보니 각 객체마다 할 일을 분담시켰죠?

메인프레임 윈도우는 실제 자기가 해야하는 일(메뉴,툴바,상태바등을 생성시키고..윈도우를 제어하는
일)은 기본으로 하고 거기다가 사용자가 확대해라, 이동해라 하는 명령을 받을 것입니다.
우리는 이 명령을 메뉴와 툴바에 있는 아이콘 둘다를 이용해서 받을 수 있도록 해야겠죠.....

두 번째 뷰 객체는 실제 그려주는 일을 합니다... 앞으로 뭔가 그리는 일은 모두 뷰가 할 것입니다..

도큐먼트는 아직 이용치 않을 겁니다..

프로그램을 구동시키는 객체는 할 일을 정의하지 않았습니다..우린 가 있으니까요...

각 객체마다 역할을 분담시켰으면 이를 클래스로 구현해야죠?
그런데 이를 우리가 일일이 만들 필요가 없죠...MFC가 있으니까요...
MFC에 있는 클래스를 가져다가 내용을 조금 빠꿔서 쓰면 되니까요..

어떤 클래스를 사용해야겠습니까?

예~~눈치 채셨겠지만 AFX클래스 모두가 필요하지요?
그럼 이클래스에서 상속받은 파생클래스를 만들어야겠군요...
우리가 직접해도 상관없지만 그럴필요가 있겠습니까? 를 통해서 간단히 파생클래스를
만들면 되겠죠....

정리하자면 메인프레임윈도우 객체는 C, 뷰객체는 CView, 도큐먼트객체는 CDocument,
프로그램을 구동시키는 객체는 C클래스에서 표현한다는 말이죠..

그런데 실제로 그림을 그리는 뷰에서는 하나의 클래스가 더 필요합니다..우리가 지금 사각형을
그리려고 하는데...이 그래픽과 관련된 기본적인 클래스가 있습니다.. CDC라는 클래스가 있는데요..
이에 대해선 프로그램을 만들면서 설명하고요...우리가 이 클래스를 안다고 가정하고 계속 하지요..

각 역할분담을 한 객체를 클래스로 구현한다는 것까지 했죠?
그런데 우리가 이들 AFX클래스에서 왜 상속받아 파생클래스를 만들었죠?

예~ 당연히 클래스에 뭔가 더 추가하고 멤버함수도 오버라이딩하고 뭐 그럴려고 한거죠...
이제 우리가 해야 하는 일은 뭡니까?

프로그램을 짜면 되죠...
사실, 괭장히 복잡한 프로그램을 만들 때는 프로그램을 직접 짜는(즉, 코딩과정) 시간은 전체
프로그램을 개발하는 과정중에 극히 일부입니다...

가장 많은 시간이 소요되는 것이 디버깅인데요.. 이 디버깅이라는게 어떤제품을 개발해 놓고
우리가 정의한 기능을 완전히 수행하지 못할 때 이를 고치는 과정인데요.. 이 과정이 가장 긴 시간을
필요로 합니다... 보통은 그렇죠...

그런데 이 디버깅이란게..실제 프로그램을 계획/설계하는 과정과 깊은 관련이 있는데요..
상식적으로 생각해 봐도 처음부터 제대로 잘 설계했다면 하자가 별로 없겠죠..
그래서 프로그램 개발 초기단계에 하는 프로그램 설계(Design)부분이 중요하고 이를 제대로 하는 것
또한 어렵고 복잡한 작업입니다..

저는 지금 솔직히 말하면 대충한거나 다름없죠...
지금 이런 간단한 프로그램 만들면서...게다가 여러분들의 귀중한 시간뺐으면서..프로그램 개발제안서
니 자료흐름도니 플로우차트니 경제성 분석이니 하는걸 할 필요가 없죠...

이런 내용은 소프웨어 엔지니어링(공학)책에 자세히 나와 있습니다... 관심있으신 분들은 참고하세요..
대형 프로젝트에는 꼭 필요한 내용이지요..

어쨌든 다음장에는 실제로 프로그램을 만들어 보도록 하겠습니다..



Visual C++ 6 강좌(036)



11.AFX 예제 프로그램 - .exe (계속)


이제 실제로 프로그램을 만들어 보죠...

기능적 정의가 끝났기 때문에 이제는 프로그램의 틀을 을 이용해서 만들고 가
만들어 놓은 AFX클래스의 파생클래스를 가지고 프로그램을 만들면 되겠죠..

보통의 경우 File메뉴에서 new(Ctrl-N)를 선택하면 다이얼로그 박스가 뜨지요...
박스가 뜨면 projects탭에서 MFC (exe)를 선택하고 project name에 원하시는 이름을 적습니
다. 이 이름은 가 AFX클래스에서 상속받아 만든 파생클래스의 이름과 실행파일,프로젝트
이름, 생성되는 파일들의 폴더이름등에 영향을 미치니 프로그램을 설명해 줄 수 있는 좋은 이름을
지어주는 것도 상당히 중요한 일이죠...

저는 이라고 하겠습니다.. 그 밑에 보면 Location이 있는데... 이는 새로 생길 프로젝트에
모든 파일들이 저장될 경로를 적어주는 곳인데.. 처음에 한번 정해주면 그다음에는 그 곳에 프로젝트
와 같은 이름의 폴더를 자동적으로 생성하여 주니까 크게 신경 안써도 되죠...

그리고 그 밑에는 Create new workspace 라는 이름의 라디오 버튼이 있는데.. 디폴트(초기값)로 선택
되어 있습니다.. 보통의 경우 는 처음 프로젝트를 생성할 때 사용하니까요... 물론 그렇지
않는 경우도 있지만요...(사실 나중에 가면 많아지게 되죠...)

플랫폼은 Win32로 되 있으니 건들이지 말고...OK 버튼을 누릅니다...

그 다음에는 어떤게 있죠? 앞에서도 얘기했지만...SDI로 만들꺼냐..MDI로 만들꺼냐..아니면 Dialog
based로 만들꺼냐 라는 걸 묻죠?

MDI에 대해서 하기전까지는 SDI로 하죠...
그 밑에는 리소스를 어떤 언어로 사용할꺼냐고 물어보는데...디폴트가 영어로 되어 있죠...그냥
그대로 하면 됩니다...

참고적으로 Visual C++ 5이하 버전에서는 프로그램을 인스톨 시키면 한글이 지원되지 않습니다..
한글 리소스를 사용할 수 없다는 얘기구요.. 이는 메뉴등의 이름을 한글로 쓰면 나중에 실행파일을
실행시켜보면 한글이 깨져서 도무지 알아볼 수 없다는 말입니다...

VC++6부터는 한글리소스가 자동적으로 인스톨되니 이를 사용하시는 분들은 별 불편없으시겠지만요..
그 이하 버전을 사용하시는 분들은 한글 리소스를 사용하기 위해선 별도의 작업을 필요로 합니다..

뭐 그렇다고 프로그래밍작업을 다르게 해야 한다는 말은 아니구요.. 파일몇개를 어떤 폴더안에 복사
만 하면 되죠... 이에 대한 설명은 자료실에 올려놓도록 하겠습니다...
제목은 대충 "vc++5이하버전에서 한글리소스 사용하기"정도가 될 것 같군요....

SDI까지 선택하고 나면 뒤쪽에는 특별히 우리가 건드릴 내용이 없으므로 Finish버튼을 누릅니다..
그다음에는 프로젝트 정보를 보여주는 창이 보일텐데.. 우리가 선택한 내용들은 보여주는 것이지요..
제대로 되 있다면 OK버튼을 누르면 워크스페이스에 뭐가 잔뜩 생겼을 겁니다...

여기까지 했다면 우리는 일단 프로그램의 뼈대는 만든 셈이죠...

class view탭을 선택하여 어떤 파생클래스들이 만들어 졌는지 보세요...

AFX클래스에서 상속받은 파생클래스가 4개있고...C라는 클래스가 더 있군요...
Global에는 theApp라는 C클래스의 인스턴스가 전역변수로 선언되어 있습니다..

지금까지는 우리가 다 배운 내용이지요?

여기다가 우리는 이 프로그램이 수행할 기능들을 넣어줄 겁니다..

우리가 넣어줄 기능이란게.. 사실 별거 아니잖아요..클라이언트영역에 마우스를 클릭하면 쬐맨한
사각형이 생기고 메뉴에서 확대를 선택하면 확대해서 보여주고 뭐 대충 이런거잖아요?

그럼 우리는 여기서 어떤일을 제일 먼저 해야겠습니까?

마우스를 클릭하면 사각형을 그려주는 기능의 함수를 만들어야겠다구요?

내 아주 좋습니다... 하지만 더 중요한건 이런 기능을 어떤 클래스에서 하게끔 하느냐를 먼저 정해
야 합니다.. 잊지 마세요.. 클래스는 자기의 일만 열심히 하면되게끔 만들어야 됩니다..
자기의 일이란건 객체와 큰 관련이 있지요?

무슨 얘기냐 하면.... 우리가 클라이언트 영역에 마우스를 클릭하면 쬐맨한 사각형을 그 마우스 위치
에 보여준다고 했으니 이는 뷰객체가 해야되는 일이란거죠... 이 객체를 표현한 클래스가 CView이고
CView에서 상속받은 파생클래스가 C이니 이곳에다 이 기능을 넣어주어야 한다는 말입니다.

아시겠지요?

그럼 이런한 기능을 하는 함수를 만들어야겠군요...

어떻게 만들면 되겠습니까? 지금까지 배운내용을 한번 상기해 보세요...

우리가 함수이름을 이라고 한다면, C클래스를 선언한 헤더파일 .h에
이 멤버함수를 선언하고 다시 C의 정의부분인 .cpp에 이 멤버함수를 정의
하면 되겠군요... 휴~~~~~~

함수를 매번 만들 때마다 이 작업을 하는 것이 그리 만만치는 않을을 같군요...
그래서 아주 쉬운 방법이 있습니다..

워크스페이스에서 C클래스위에다 마우스를 놓고 오른쪽 마우스버튼을 누르면 팝업메뉴가
나오는데요... 거기에 보면 Add Member Function...이라는 메뉴가 있습니다.. 이를 누르면..
함수의 리턴값 타입과 함수이름 인자등을 선언할 수 있는 다이얼로그 박스가 나오는데.. 여기다가
위 내용을 적어주면, 마우스가 올려져 있는 클래스의 멤버함수로 등록이 되서 헤더파일과 cpp 파일에
우리가 일일이 적어주지 않아도 자동적으로 멤버함수의 선언부분과 정의부분이 생겨나기 때문에..
우리는 다른 거 신경쓸 것 없이 멤버함수 정의부분에 우리가 넣고자 하는 기능을 넣어주면 되는 거죠..

팝업메뉴를 유심히 보신분들은 알겠지만.. Add Member Function밑에는 Add Member Variable...이라는
메뉴가 있습니다.. 즉 멤버변수도 이와 동일한 방법으로 선언할 수 있다는 얘기겠죠...



Visual C++ 6 강좌(037)



11.AFX 예제 프로그램 - .exe (계속1)


이쯤에서 한가지 생각해 볼 만한 내용이 있습니다...
지금 우리가 이라는 함수를 어떻게 정의했지요? 마우스가 클릭할 때 마다 쬐맨한 사각형을
그려주는 함수라고 정의했지요?

그런데...윈도우에서 마우스를 클릭하면 어떤 일이 일어나지요?
네~~~윈도우 메시지가 발생하지요? WM_LBUTTONDOWN이라는 메시지라는 메시지가 발생합니다...

그러면 이 메시지가 발생할 때 즉, 마우스 왼쪽 버튼이 클릭되었을 때 우리가 무슨일을 하고 싶다면
이 메시지의 핸들러 함수를 오버라이딩하면 된다고 배웠죠?

그럼 이 메시지 핸들러 함수에 그림을 그리는 기능을 넣어주면 되겠군요....

그렇다면 이라는 함수를 만들어 마우스가 클릭될 때마다 사각형을 그려주고자 했던 우리의
생각이 틀렸군요...

만약 제가 앞에서 마우스가 클릭될 때마다 사각형을 그려주는 함수를 이라고 정의하자고 했을
때 뭔가 이상하다고 생각하신 분들은 공부를 열심히 하신 분들이고.. 그냥 "허~~그래 정의 하자"라고
생각하신분들은 좀더 분발하셔야 할겁니다...

그럼 를 사용해서 메시지핸들러 함수를 오버라이딩 해야겠지요?
그런데... 이 사각형을 그리는 루틴이 프로그램에서 또 어디서 사용될 지 아무도 모르잖습니까?
그래서 다른 부분에서 사각형을 그리는 부분이 필요해 질 때 이 메시지 핸들러 함수를 호출한다면..
뭔가 좀 이상하군요...

그래서 우리는 이렇게 결론을 내야 합니다...

"마우스를 클릭할 때마다 쬐맨한 사각형을 그리도록 하려면.....쩝...."

"이러한 기능을 뷰 오브젝트(객체)가 하는 것이 바람직하니까...C에다가 이러한 기능을
넣어주자"

"그리고 마우스가 클릭될 때마다 어떤 일을 하고 싶으면 WM_LBUTTONDOWN메시지가 발생할 때 자동적
으로 호출되는 메시지 핸들러 함수를 오버라이딩 하면 되겠구나.."

"그리고 이 사각형을 그리는 루틴이 다른곳에서 또 쓰일 경우를 생각해서 이 기능을 하는 함수를
C클래스의 멤버함수로 선언해 주고 이를 정의하면 되고... 이 함수를 WM_LBUTTONDOWN
메시지의 핸들러 함수에서 호출해 주면.... 마우스를 클릭할 때마다 쬐맨한 사각형을 그릴 수
있겠군.....쩝"

사실 이런 설명은 그림을 그려서 설명하면 간단하기 그지없는데... 그럴 상황이 못되는 군요...
2판때나 가능할 만한 얘기지요... 안타깝습니다...
그러니 직접 그림으로 그려가며 이해하시면 되겠지요....

그럼 우리는 메시지 핸들러 함수를 오버라이딩 해야 하고...함수를 C의 멤버
함수로 등록시킬 것입니다...

여기서 우리가 그림을 그리는 루틴을 에다 넣어야 하는데...MFC를 이용해서 그림을 그리는
방법을 알 필요가 있습니다... 간단하니..그냥 공식처럼 외우기만 해도 상관은 없습니다... 뒤에
그래픽에 대해 설명할 때 좀더 자세히 할 테니까요....

1.그래픽 기초

윈도우에서 1Cm짜리 선을 하나 그릴려고 한다면...정말 시시한 출력에 비해 너무나 많은 일을 해야
합니다.. 선 색깔을 검정으로할지 빨강으로 할지도 결정해야 하고...점선으로 할지 실선으로 할지..
배경그림에 덮어쓸지 이런저런 합성을 할지...등등등...여러 가지로 고려해야 할 점이 많지요....

이런 것을 모두!! 매번!! 프로그래머가 직접!! 해야 한다고 하면... 짜증나는 일이 아닐 수 없습니다
그래서 글자든 그림이든 이런저런 옵션(선택사항)을 디폴값을 설정하여 한군데에 모아놓고...
프로그래머가 바꾸고 싶은 부분만 살짝 바꾸고..원래대로 다시 해 놓으면 될 수 있도록 준비되어 있
는게 있습니다...

디바이스 컨텍스트(Device 하는 구조체 인데요...윈도우가 이와 같은 방법을 사용
합니다...
앞으로 DC라고 부르겠습니다...
이를 이용하면 아무 것도 건드리지 않고 초기값으로 그림을 그릴 수도 있구요...아니면 조금만 바꿔
서 사용하고 원래대로 다시 돌려 놓으면 되기 때문에 편리하기 그지 없죠...

물론 처음 프로그래밍언어를 공부하는 사람이라면...참 드럽게 공부할 게 많구나...하는 생각도
들겠지만요...사실 말 그대로 드럽게 공부할 게 많습니다...미리 단단히 마음의 준비를 해야 되죠..

그럼 MFC를 이용해서 실제 그림을 그린다고 한다면...CDC라는 클래스를 사용하면 됩니다...
CDC는 앞에서 설명한 DC와 이와 관련된 모든 그래픽 함수, 변수를 한데 묶어 놓은 클래스 인데요..
이 클래스를 이용하면 그림을 그릴 수 있습니다...

그럼 거두절미하고 결론부터 얘기하죠....

CDC *pDC = GetDC(); file://DC를 얻는다...
pDC->Rectangle(0,0,10,10); // DC를 사용한다.
ReleaseDC(pDC); // DC를 반환한다..

DC도 윈도우의 소중한 자원입니다... 그러니 우리가 이를 사용하려면 윈도우로부터 얻어와야겠죠?
윈도우에서 DC를 얻어오는 함수가 GetDC입니다...그러면 이 함수는 DC의 주소를 반환하는데요...
이 얻어 온 DC를 이용해서 우린 그림을 그리는 거죠...

그래서 맨처음 문장은 GetDC함수가 반환한 DC의 주소를 CDC의 인스턴스인 pDC라는 포인터 변수에
넣습니다.. 그리고 우리는 이 pDC라는 CDC의 인스턴스를 사용해서 사각형을 그리죠...
그리고 이를 다시 반환합니다...

그래서 GetDC와 ReleaseDC는 항상 같이 있어야 합니다...
그런데.. 매번 그림을 그릴 때마다 이렇게 얻고 반환하고 하는 단순작업을 계속해야 한다는 것도
귀찮지요...프로그래머는 상당히 게으른 사람이니까요...

그래서 CClientDC라는 클래스를 소개하고자 합니다... 자 서로 인사하세요...쑥스러워 하시긴...

CClientDC라는 클래스는 CDC를 상속받은 파생클래스인데요... 그러니 CDC의 모든 내용을 다 가지고
있겠죠? 그리고 CClientDC의 생성자 함수에서 GetDC를 호출하고 소멸자 함수에서 ReleaseDC를 호출
합니다...
그러니 이 클래스의 인스턴스를 만들면 GetDC함수가 호출되고 이 인스턴스가 소멸되면 ReleaseDC가
호출되니 우리가 DC를 얻고자시고 할 필요가 없습니다....다음과 같이 사용하면 되죠...

CClientDC dc(this);
dc.Rectangle(0,0,10,10);

아주 간단해 졌죠? 그냥 CClinetDC클래스의 인스턴스만 하나 만들어주면 되죠....
dc(this)라는 것은 인스턴스를 만들 때 생성자 함수의 인자로 this를 넘겨주라는 얘깁니다...

그래픽 작업을 하는데 어느 윈도우에서 할지 모르니까...윈도우의 주소를 this를 이용하여 넘겨준
겁니다...어쨌든 위와 같이 하면 되요...

다음 페이지에선 실제 프로그램을 짜고 실행시켜 보겠습니다...




Visual C++ 6 강좌(038)



11.AFX 예제 프로그램 - .exe (계속2)


2.자~ 짭니다...

사각형을 그려주는 기능을 하는 함수를 선언해야겠죠?
어떻게 하죠? 그러니까 어떤 인자를 받고 어떤 타입의 데이터를 반환할꺼냐는 얘깁니다...

그거야 프로그래머 맘데로이지만요...
이런식으로 하죠...메시지 핸들러 함수-아마도 OnL이 되겠죠?-에서 을 호출할텐데
이때 마우스가 클릭된 좌표를 인자로 넘겨줘야 그 위치에 그림을 그릴 수 있겠죠?
그리고 반환해야 할 값이 뭐 있습니까? 궂이 반환해야 되는 값은 없는 것 같군요...

그러니 이런식으로 하죠...void (CPoint point) ....쩝...

CPoint가 처음 나온거 같죠? 대충 짐작하셨겠지만...좌표와 관련된 클래스이지요... 그리고 CObject
에서 상속받은 파생클래스가 아닙니다..MFC 카테고리엔 Simple Value Types에 있지요...
이 카테고리에는 CPoint외에도 CRec, CSize, CString, CTime, C이 있습니다... 이름만 봐도
대충 짐작이 가는 클래스들이지요...

어쨌든 CPoint 클래스는 다음과 같이 이용할 수 있죠...예를 들어 좌표를 사용하자면...
CPoint point; file://인스턴스 생성
point.x =0; point.y=0; file://인스턴스를 이용하여 좌표에 값을 입력

위와 같이 사용할 수 있다는 겁니다...

왜 CPoint를 사용했나면요... OnL 즉 WM_LBUTTONDOWN메시지의 핸들러 함수가 다음과 같이
선언되어 있거든요...

void OnL(UINT nFlags, CPoint point)

그러니 OnL함수에서 함수를 호출할 때 point를 인자로 넘겨주면 에서 이
좌표를 이용해서 그림을 그릴 수 있으니까요...

그럼 앞에서 설명한 방법으로 C클래스에 이라는 멤버함수를 추가시켜 봅시다.

Add Member Function을 클릭하면 다이얼로그 박스가 나오는데....


Function Type(리턴값의 데이터유형) : void 입력 -> TAB키

Function Declaration (함수선언) : (CPoint point)

Assess : public 선택

static, virtual 란 비워둠...

앞에서 다 설명한 부분이니 public이니 static이니 virtual이니 하는 말들은 다 아시겠죠?

이렇게 입력하고 OK버튼을 누르면 .h에 멤버함수가 선언되고...
.cpp에 함수의 틀이 만들어져 있습니다...

그럼 워크스페이스에서 C밑에 를 더블클릭하면 함수의 틀이 만들어져 있습
니다.. 다음과 같이요...

void C::(CPoint point)
{

}

내용만 없고 틀은 다 만들어져 있지요? 얼마나 간편합니까....

그럼 이안에 우리가 원하는 기능을 넣어주면 되죠...
우리가 원하는 기능이란게...쬐맨한 사각형을 그리는 거니까...

DC를 얻고 사각형을 그리면 그걸로 끝!!

그럼 다음과 같이 하면 되겠군요...사각형 크기는 (10x10) 정도로 합시다...

#define SIZE 5

void C::(CPoint point)
{
CClientDC dc(this);

dc.Rectangle(point.x-SIZE, point.y-SIZE, point.x+SIZE, point.y+SIZE);
}

이런식으로 하면 마우스가 클릭된 점을 중심으로 가로 세로 10 X 10의 사각형을 그릴 수 있겠죠?

자 이젠 뭐를 하면 되지요?

예 마우스가 클릭될 때 호출되는 메시지 핸들러 함수를 오버라이딩해야죠?
그러니까 이 메시지 핸들러 함수에서 함수를 호출하면 된다는 얘기죠...
그러면 마우스를 클릭할 때마다 쬐만한 사각형이 그려 질테니까요...

메시지 핸들러 함수의 오버라이딩은 로 하면 간편하다고 하였죠?

그럼 Ctrl-W를 하면 클래스위저드 가 뜨는데요...

Message Map 탭을 클릭하고..(사실 대부분 디폴트가 여기죠..)
Class Name 이 C인지 확인하고 ....
Messages 리스트 컨트롤에서 WM_LBUTTONDOWN을 선택하고...
Add Function을 누르던지...WM_LBUTTONDOWN을 더블클릭하던지 하면 메시지 핸들러 함수가 자동적으로
C클래스에 생깁니다...

그러면 우리는 헤더파일에 선언할 필요도...매세지맵에 일일이 등록할 필요도...없습니다...
그럼 OnL함수를 볼까요? 역시 그 틀이 다 만들어져 있죠?

void C::OnL(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default

CView::OnL(nFlags, point);
}

우린 file://TODO 어쩌구 하는 자리에 함수를 호출해 주시만 하면 되는 거죠...
그러면 이런 모양이 되겠죠...

void C::OnL(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default

(point);

CView::OnL(nFlags, point);
}

이러면 끝입니다... 눌린 좌표 point만 넘겨주면 이 그 좌표를 참조하여 그림을 그리겠죠...

자~~ 그러면 F7을 누르고 .exe - 0 error(s), 0 warning(s)라는 메시지가 나오면 F5를 눌러
실행시켜 보세요...

어떠십니다...정말 인내는 쓰고 그 열매는 달죠? 사실 쬐끔 달죠...

이제 여기에 몇가지 괜찮은 기능을 넣어 보겠습니다..
확대해서 그릴 수 있도록 해보죠...
해보면 이것도 참 별거 아니거든요...



Visual C++ 6 강좌(039)



11.AFX 예제 프로그램 - .exe (계속3)


프로그램에 확대하는 기능을 넣어보죠...일종에 버전업이군요...

먼저 메뉴에 보기메뉴에서 확대크기와 보통크기로 그리는 메뉴를 만들어야겠죠?
그리고 이 메뉴가 클릭되면 그때 부턴 그림을 확대 또는 보통크기로 그리게 되구요..
또하나...중요한건 사용자가 아무 명령도 내리지 않으면 보통크기로 그려야 하니까..
디폴트로 보통크기로 그리도록 해야겠군요...

이정도면 기능의 정의는 다 된거죠...

그럼 먼저 메뉴바에 Magnify, Normal이라는메뉴를 넣어야겠군요...

그대로 따라해 보세요...

워크스페이스에서 Resource View 탭을 선택하고 Menu항목에서 IDR_MAINFRAME[English(U.S.)]을 더블
클릭해 보세요..

그러면 오른쪽 창에 메뉴바가 보이죠... 이를 리소스 편집기를 이용하면 비주얼 하게 리소스를 편집
할 수 있습니다...정말 편하죠...

그런데 IDR_MAINFRAME이란 말이 뭘까요? 이는 이 메뉴바의 리소스 ID입니다. IDR은 즉 ID Resource를
의미하는 거죠... 그리고 뒤에 있는 English(U.S.)은 우리가 에서 리소스에서 사용하는
언어를 영어로 선택했기 때문이죠... 지금 제가 VC++5를 기준으로 실습하기 때문에 처음엔 영어로
하고 다음부턴 한글로 하겠습니다... 한글 리소스 사용법은 자료실에서 다운로드해서 보세요...

자 그럼 메뉴바에서 맨 오른쪽 빈칸을 클릭하면 Menu Item Properties창이 뜨는데..
Caption 에 Size라고 입력하고 엔터를 칩니다..

그렇게 하면 Size라는 메뉴밑에 빈칸이 생기는데 거길 다시 클릭하면
Menu Item Properties창이 뜨죠?
거기에 ID란에는 메뉴항목의 ID를 넣어주면 되고 caption부분엔 메뉴이름을 넣어 주면 되죠..
메뉴이름을 Magnify라고 하고 ID를 ID_MAGNIFY라고 합시다...

동일한 방법으로 그밑에는 Normal, ID_NORMAL이라는 속성을 가진 메뉴를 만듭니다...

자~~메뉴 편집은 끝났습니다...
그러면 프로그램 소스를 조금 바꿔야겠죠?

어떻게 하면 되겠습니까?

예~~~뭐 확대를 얼마로 할지를 정할 때 쓰이는 변수를 하나 만들어야겠군요...
뭐 변수이름을 Mag이라고 하죠... 그래서 Mag = 1이면 Normal이고 Mag = 2이면 Magnify에 해당되겠군
요 그래서 int Mag이라는 변수를 C의 멤버함수로 선언해야겠죠?

선언하는 방법은 멤버함수를 새로 선언할 때와 마찮가지니 설명하지 않겠습니다..
멤버변수를 선언했으니 초기화를 시켜야 합니다... 초기화 시키는 데 적당한 곳은 생성자 함수죠..
그러면 C의 인스턴스가 생성될 때 멤버변수도 초기화되어 메모리에 잡히니까요...

사용자가 아무 것도 명령하지 않았다면 디폴트로 Normal사이즈로 그릴 테니까

그럼 생성자 함수에 이런식으로 넣으면 되겠군요....


CDrawRecView
C()
{
Mag = 1;
}

이렇게 초기화 시키고 에서 이 변수를 참조할 수 있도록 하면 되겠군요...

또 메뉴에서 Normal이나 Magnify를 선택하면 COMMAND 메시지가 발생하죠?
그럼 우리는 이 메시지가 발생할 때 호출되는 함수를 만들어 거기다가 원하는 기능을 넣어주면 되죠..

그리고 그 기능이란게.. 정말 별거 아닙니다...Normal 이란 메뉴가 클릭되었을 때 호출되는 핸들러
함수에는 Mag = 1;이라는 문장을 넣어주면 되고 Magnify라는 메뉴가 클릭되었을 때 호출되는 핸들러
함수에는 Mag =2; 이라는 문장을 넣어주면 그걸로 끝이죠...

그리고 에선 Mag=1일 땐 보통크기로 그림을 그리고 Mag=2일 땐 2배크기로 그리려주는 루틴을
넣어주면 되는 겁니다...

자 그러면 메뉴를 클릭하였을 때 발생하는 메시지를 핸들링 하는 함수를 만들어야겠군요...

그럼 Ctrl-W 하여 클래스위저드 창을 띄웁시다...

다시 Message Map 탭에서 Class Name이 C인지 확인하고 ...Object IDs 리스트박스에서
우리가 만들어 놓은 ID_NORMAL을 찾아 선택합니다.. 그리고 Messages 란에 COMMAND를 더블클릭하면
Add Member Function 이라는 쬐맨한 창이 뜨죠? 이 창은 이 메시지 핸들러함수의 이름을 우리가
정할 수 있도록 합니다... 하지만 디폴트로 이라고 되있죠?

보통의 경우 그냥 주는 이름대로 사용하는 것이 속편하고 좋은 방법입니다.. 특별한 경우가 아니라면
그냥 엔터만 치면 되죠... 하지만 WM_로 시작하는 윈도우 메시지 핸들러 함수는 이름이 정해져 있는
반면 COMMAND메시지는 그 이름을 우리가 정할 수 있다는 얘기죠... 그러니 뭐 오버라이딩이니 어쩌니
도 없구요.. 전부 우리가 정의해 줘야 합니다...

함수의 정의부분을 보면 틀이 다음과 같이 만들어져 있습니다....


void CDrawRecView
()
{

}

여기다가 우리는 Mag =1이라고 만 하면 끝이 납니다...즉 확대를 1로 하겠다... 즉 보통사이즈로
그리겠다는 것이죠...


void CDrawRecView
()
{
Mag = 1;
}

같은 방법으로 ()라는 함수에 Mag =2; 를 넣어주죠....

자 그러면 사각형을 그리는 함수만 고쳐주면 모든 일이 끝나겠죠?

어떻게 고칠까요... 정말 간단합니다... 아래와 같이 해주면 끝이죠...

#define SIZE 5

void C::(CPoint point)
{
CClientDC dc(this);

if(Mag == 1)
dc.Rectangle(point.x-SIZE, point.y-SIZE, point.x+SIZE, point.y+SIZE);
else
dc.Rectangle(point.x-SIZE*Mag, point.y-SIZE*Mag, point.x+SIZE*Mag, point.y+SIZE*Mag);
}

물론 위와 같이 한 한 이유는 1이 아니면 Mag의 값은 2밖에 가질 수 없으니 이렇게 한겁니다..

그럼 한번 실행해 보세요...조금 나아진 것 같죠?

이 예제에서 우리는 어떤 기능을 어떤 클래스에서 수행하도록 할 것인가? 메시지 핸들러 함수를
어떻게 사용하는가 리소스 편집은 어떤 식으로 하는가? COMMAND 메시지를 어떻게 사용하는가?
멤버변수와 멤버함수를 어떻게 추가시키고 사용하는 가에 대해 배웠습니다...

참고로 Mag라는 변수는 C의 멤버변수이므로 클래스 내부에서는 자유롭게 참조할 수 있다는
것 아시죠? 이런 거 헷갈리면 안됩니다...

댓글