. 메뉴 관리

MDI 프로그램은 보통 메뉴가 두 벌이다. 왜냐하면 문서를 편집중일 때와 그렇지 않을 때 필요한 명령의 종류가 달라지기 때문이다. 대표적인 MDI 프로그램인 비주얼 스튜디오를 보자. 프로젝트가 열려 있을 때와 그렇지 않을 때의 메뉴 모양이 달라진다.

상식적으로 생각해보면 프로젝트 작성중이 아닐 때는 빌드나 디버그 따위의 메뉴 명령이 필요없다. 나머지 도구, 편집 메뉴도 안을 열어 보면 대부분 비어 있거나 사용 금지되어 있을 것이다. 당근도 마찬가지다. 문서편집을 하지 않을 때는 편집, 저장, 검색 따위의 명령이 불필요하며 오로지 문서를 열거나 새로 만드는 것만이 가능하다.

이런 이유로 일반적인 MDI 프로그램은 문서 작성중일 때와 비어 있을 때의 메뉴를 각각 만들어 두고 현재 상황에 맞는 메뉴를 실행중에 교체해 가며 사용한다. 물론 하나의 메뉴만 가지고도 불필요한 명령을 사용 금지시키거나 숨길 수도 있다. 그러나 필요한 명령의 종류가 워낙 판이하게 다르기 때문에 아예 메뉴를 두 벌 가지는 것이 오히려 더 효율적이다.

당근 프로젝트는 IDR_MENU1, IDR_MENU2 두 벌의 메뉴를 가지고 있으며 이 두 메뉴를 WinMain의 선두에서 미리 읽어 hMenu1, hMenu2 핸들에 대입해놓는다. 메인 윈도우의 lpszMenuName은 일단 빈 상태인 IDR_MENU2로 지정되어 있으나 어차피 실행중에 다시 바뀌기 때문에 큰 의미는 없다. 다만 다음에라도 실행 직후에 빈 문서창을 만드는 기능을 옵션으로 제공할 경우 사용자가 이 옵션을 해제했을 때를 고려하여 IDR_MENU2를 디폴트 메뉴로 지정해놓은 것이다.

메뉴가 교체되는 시기는 DGChildProc에서 차일드를 생성하거나 파괴할 때이다. 차일드가 없는 상태에서 처음 만들어질 때 hMenu1으로 교체하고 마지막 차일드가 파괴될 때 hMenu2로 다시 교체한다. g_ChildNum 0에서 1이 될 때와 1에서 0이 될 때만 메뉴를 교체하며 그 나머지 경우, 예를 들어 문서 하나를 편집하는 중에 하나가 더 열리는 경우는 교체하지 않는다. 이 조건 판단을 하기 위해서는 항상 현재 열린 차일드 개수를 유지해야 하며 이 역할을 g_ChildNum전역 변수가 하고 있다.

메뉴를 교체할 때는 SetMenu 함수를 사용할 수 없으며 반드시 WM_MDISETMENU 메시지를 MDI 클라이언트로 보내야 한다. 왜냐하면 메인메뉴를 교체하는 것뿐만 아니라 윈도우 메뉴도 같이 지정해야 하기 때문이다. 예제에서는 5번째 팝업인 창 메뉴를 윈도우 메뉴로 지정하고 있다. 당근을 실행해놓고 문서가 있을 때와 그렇지 않을 때의 메뉴를 비교해보자.

 

문서가 열려 있지 않을 때는 편집기능을 쓸 수가 없으므로 편집 메뉴가 통째로 사라진다. 파일 메뉴를 열어 보면 저장이나 인쇄 등의 명령은 사라지고 새 파일, 파일열기 등만 남아 있을 것이다.

 

이상 여기까지 Dangeun 프로젝트의 첫 번째 예제를 분석해보았다. MDI의 기본 형태를 갖추었을 뿐 아직까지 특별히 기능이 더 들어가지는 않았지만 이어지는 실습에서 이 예제를 시작점으로 하여 계속 기능을 추가해 나갈 것이다. 그래서 다음 실습을 직접 진행해보기 위해서는 이 예제 전체를 완전하게 이해하는 것이 중요하다. MDI 관련 문법, 여분 메모리 사용방법 등 모르는 내용이 있다면 조금 쉬었다 가는 셈치고 반드시 다른 자료를 찾아보기 바란다.

ApiEdit.cpp도 물론 계속 만들어지지만 ApiEdit9까지 작성된 내용을 그대로 계승했으므로 지금까지 실습한 방식대로 계속 실습을 진행해 가면 된다. 하지만 지금부터는 ApiEdit.cpp보다는 Dangeun.cpp에 코드가 더 많이 작성되기 때문에 이 단계에서 Dangeun.cpp를 완전히 이해하지 못하면 이후의 실습이 어려워질 것이다. 길지도 않으므로 찬찬히 훑어보고 이해가 안가는 부분이 있는지 다시 한 번 더 살펴보기 바란다.