IT/MFC

MDI(Multi Document Interface)

KSI 2005. 6. 24. 05:38

오늘은.. 드디어 멀티 도큐먼트..

먼저 SDI 때와 다른점을 살펴보면..

 

CMainFrame 클래스가CMDIFrameWnd를 상속 받는다.

그리고CChildFrame 클래스는CMDIChildWnd를 상속받는다.

CMDIFrameWndCMDIChildWnd아버지 클래스는 CFrameWnd이다.

 

App 클래스의InitInstance함수를 보면

CMultiDocTemplate* pDocTemplate;
 pDocTemplate = new CMultiDocTemplate(
  IDR_BMPTYPE,                                  // 메뉴와 연결된다.
  RUNTIME_CLASS(CMDItest2Doc),
  RUNTIME_CLASS(CChildFrame),          // 차일드프레임..
  RUNTIME_CLASS(CMDItest2View));
 AddDocTemplate(pDocTemplate);

 // create main MDI Frame window
 CMainFrame* pMainFrame = new CMainFrame;       // 부모 프레임..
 if (!pMainFrame->LoadFrame(IDR_MAINFRAME))    // 부모 프레임의 메뉴
  return FALSE;
 m_pMainWnd = pMainFrame;

 // Enable drag/drop open
 m_pMainWnd->DragAcceptFiles();

 

* PreCreateWindow 함수.

  프레임윈도우가 생성될때, 윈도우 속성을 바꿔주려면 PreCreateWindow함수를

  오버라이딩하여 넘어온 인자를 수정하면 윈도우 속성이 변경된다.

 

그리고 차일드프레임의 한번 봐줘야 할 함수들은..

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
 // 여기서 cs를 변경시키면 윈도우 속성이 변경된다.

 if( !CMDIChildWnd::PreCreateWindow(cs) )
  return FALSE;

 cs.style = WS_CHILD | WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU
  | FWS_ADDTOTITLE | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;

 return TRUE;     // CREATESTRUCT 구조체를 이용해 윈도 스타일을 셋팅..
}

void CChildFrame::ActivateFrame(int nCmdShow) // 활성화되었을때 실행되는거였던가 ㅡㅡa
{
 // TODO: Modify this function to change how the frame is activated.

 nCmdShow = SW_SHOWMAXIMIZED;
 CMDIChildWnd::ActivateFrame(nCmdShow);
}

 

이제 창을 하나 더 추가 해보려면 우선..프레임과,독,뷰,  각각 클래스를 추가하여야한다.

프레임은 CMDIChildWnd , Doc 는 CDocument , 뷰는 에디트 뷰로.. 상속을 받아 생성했다.

그리고 밑에 부분을 App의 InitInstance 부분에 기본적으로 만들어진부분 밑에다가..끼어 넣는다.

헤더파일 인클루드도 빼먹지말고..

CMultiDocTemplate* pDocTemplate2;     ////////////////////////////////////
 pDocTemplate2 = new CMultiDocTemplate(
  IDR_TXTTYPE,                            // 요부분이 리소스의 메뉴와 연결..
  RUNTIME_CLASS(CMyEditDoc),    // 생성한 클래스를 만든다.
  RUNTIME_CLASS(CMyEditFrame),  

  RUNTIME_CLASS(CMyEditView));
 AddDocTemplate(pDocTemplate2);

 

그리고 텍스트 창의 데이터를 저장하거나 불러오려면.. 텍스트 뷰에 대한 Doc클래스의 

Serialize함수를 이용한다.CEditView클래스의 멤버함수인SerializeRaw함수만 호출하면

텍스트 데이터를 저장하거나 읽기를 알아서 수행한다.

void CMyEditDoc::Serialize(CArchive& ar)
{
 ((CEditView*)m_viewList.GetHead())->SerializeRaw(ar);
}

 

이렇게 하면 창이 두개가 있어 처음에 골라줘야 한다. 귀찮다.. 없애버리자..

암거나 고르면 기본적으로 창하나가 생성된다. 이것을 바꾸어 사용자가 새문서를 클릭했을때

그때 창이 생성되게 하려면 App의 InitInstance함수에서

 CCommandLineInfo cmdInfo;
 ParseCommandLine(cmdInfo);

 cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;  // 요기부분 추가..
 // Dispatch commands specified on the command line
 if (!ProcessShellCommand(cmdInfo))
  return FALSE;

 

그럼이제 새파일을 눌르면 창이 생성되게 하려면..

App에OnFileNew를 오버라이드 하여..

void CMDItest2App::OnFileNew()
{      // 오늘 소스에서는 나중에 만든 에디트뷰가 달린걸 생성하게 하였다.
 // TODO: Add your command handler code here
 POSITION pos = GetFirstDocTemplatePosition( ); // 첫번째 Docd의 Position 값을 갖고온다.
 CDocTemplate* pDocTemplate = GetNextDocTemplate(pos); //그값으로 DocTemplate 를 얻음.
 pDocTemplate = GetNextDocTemplate(pos);    // 에디트 뷰를 불러와야하니깐 한번더 간다.
 pDocTemplate->OpenDocumentFile(NULL);   // 오픈한다...NULL이면 새 파일..
}

그리고 일반뷰 창 생성 커맨드를 매뉴에다  만든다.

창이 생성되어 활성화 될때마다메뉴가 바뀌니 곳곳마다 추가한다.

그리고.. 밑에 함수..

void CMDItest2App::OnBmp()  // 여기는 App
{
 // TODO: Add your command handler code here
 POSITION pos = theApp.GetFirstDocTemplatePosition( );  //
 CDocTemplate* pDocTemplate = theApp.GetNextDocTemplate(pos);
 pDocTemplate->OpenDocumentFile(NULL); // NULL이면 새 파일..
}

전역변수theApp를 이용하여 EditFrame,일반프레임에도 똑같이 만든다..

여기까지 대충 MDI 완료.. SDI에서 하던거 다 할수 있단다..

 

* 분할 뷰에서 분할바 못움직이게 하기.

  CSplitterWnd 를 상속받아 나만의 CMySplitterWnd 클래스를 만들고 마우스 메세지를 가로챈다.

 

* 클래스의 재사용..

  클래스들을 마우스로 선택후 마우스 오른쪽버튼을 눌러Add to Gallery항목을 선택하면

  겔러리에 등록이 된다.

  다른 프로젝트에서 사용하려면 컴포넌트 추가할때처럼.. Project - Add to Project -

  Components and Control 을 선택하면 추가했을때의 프로젝트명으로 폴더가 있는데

  그안에 파일들을 추가하면 된다.

* 리소스의 재사용..

  메뉴의 파일 오픈하여 리소스파일을 불러오면 현재 리소스와 불러온 리소스가 양쪽으로 뜬다.

  그럼 남은건 카피 앤 페이스트..