본문으로 바로가기

MDI(Multi Document Interface)로 개발하기4

category 개발언어/c++ 2016. 7. 25. 11:21

앞에서  SDI로 프로젝트를 개발하고 MDI로 변환 하는 방법을

알아 보았습니다.

이장에서는 몇 가지 주제를 나누어 조금 다르게 접근 하겠습니다. 몇몇 편리한 기법을 소개 하도록 하겠습니다.

--목차--

MDI를 SDI로 변형하기(MDI to SDI)

MDI 또는 SDI 선택하기(MDI<->SDI).

MDI 확장 또는 MDI 추가

--본문--

MDI를 SDI로 변형하기(MDI to SDI)

SDI로 프로젝트를 만들고 MDI로 변경하려니 번거로운 작업이 많이 따릅니다.

Wizard로 쉽게 MDI로 프로젝트를 생성하고 MDI에서 SDI로 변경하는 방법을 설명 드리겠습니다.

MDI에서 DocTemplate을 생성하는 방법을 바꾸어 주는 것입니다.

BOOL CAppFrameApp::InitInstance()//MDI

{

…………

CMultiDocTemplate* pDocTemplate;

pDocTemplate = new CMultiDocTemplate(

        IDR_MAINFRAME,

        RUNTIME_CLASS(CAppFrameDoc),

        RUNTIME_CLASS(CMainFrame), // custom MDI child frame

        RUNTIME_CLASS(CAppFrameView));

AddDocTemplate(pDocTemplate);

……….

}

BOOL CAppFrameApp::InitInstance()//SDI

{

…………

    CSingleDocTemplate* pDocTemplate;

    pDocTemplate = new CSingleDocTemplate(

        IDR_MAINFRAME,

        RUNTIME_CLASS(CAppFrameDoc),

        RUNTIME_CLASS(CMainFrame), // main SDI frame window

        RUNTIME_CLASS(CAppFrameView));

    AddDocTemplate(pDocTemplate);

……….

}

그리고

메인프레임의 상속을 CMDIFrameWnd-> CFrameWnd 로 바꾸어 주면 됩니다.

class CMainFrame : public CMDIFrameWnd -> class CMainFrame : public CFrameWnd

그리고 Project Wizard가 생성시킨 코드 또한 바꾸어 줍니다.

예)

void CMainFrame::Dump(CDumpContext& dc) const

{

    CFrameWnd::Dump(dc);

}

이것으로 기본적인 변환은 이루어 졌습니다.

그런데 한가지 문제가 더 있습니다.

CMainFrame 에서

"MainFrame.h" 의 DECLARE_DYNAMIC(CMainFrame)

"MainFrame.cpp" 의 IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)

라고 되어 있는 것을

"MainFrame.h" 의 DECLARE_DYNCREATE (CMainFrame)

"MainFrame.cpp" 의 IMPLEMENT_DYNCREATE (CMainFrame, CFrameWnd)

와 같이 바꾸어 주어야 한다는 것입니다.

DECLARE_DYNAMIC은 실행 중 클래스 정보 제공하는 매크로인데 저것이 있어야

RUNTIME_CLASS 매크로가 정상 적으로 CMainFrame를 인식합니다.

DECLARE_DYNCREATE 는 실행 중 클래스 정보 제공하고, RUNTIME_CLASS 매크로를 이용하여 객체를 생성 가능하도록 하는 매크로 입니다.

CSingleDocTemplate
는 ProcessShellCommand()를 실행하면서 CMainFrame을 자동으로 생성시키는데 DECLARE_DYNCREATE 가 없으면 클래스를 생성할 수 없어서 SDI로 변환해도

정상동작 하지 않습니다.

DECLARE_DYNAMIC 와 DECLARE_DYNCREATE는 같이 쓸 수 없습니다.

DECLARE_DYNCREATE하나만 사용해야 합니다.

MDI 또는 SDI 선택하기(MDI<->SDI)

개인적으로 자주 사용하게 되는 기능을 추가하여 기본 골격을 만들어 놓고 그 기본 Frame위에

프로젝트의 성격에 맞게 코드를 추가하기 위해서 약간의 수정을 합니다.

"MainFrame.h"를 열어서

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

//#define FRAME_SDI

#ifdef FRAME_SDI

#define baseFRAME CFrameWnd //SDI

#else

#define baseFRAME CMDIFrameWnd //MDI

#endif

를 추가하고 CMainFrame 의 부모 클래스를 변경하여 상속을 변경합니다.

class CMainFrame : public baseFRAME

{

…..

}

CMainFrame 이 CFrameWnd 을 상속받으면 SDI CMDIFrameWnd 를 상속받으면 MDI이므로

#define FRAME_SDI
가 선언되었는지 여부에 따라 SDI및 MDI로 쉽게 가변 되도록 착안했습니다.

"MainFrame.cpp"에서도 CFrameWnd-> baseFRAME로 변경하는 작업을 해야 합니다.

예)

IMPLEMENT_DYNCREATE(CMainFrame, baseFRAME)

BEGIN_MESSAGE_MAP(CMainFrame, baseFRAME)

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

    if (baseFRAME::OnCreate(lpCreateStruct) == -1)

        return -1;

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

    if( !baseFRAME::PreCreateWindow(cs) )

return FALSE;

그 다음은 BOOL CAppFrameApp::InitInstance()에서 아래와 같이 변경하여

SDI이때의 동작과 MDI일 때의 상황을 구분하여 동작 하도록 코딩 합니다.

CAppFrameApp::InitInstance()

{

………..

#ifdef FRAME_SDI

    CSingleDocTemplate* pDocTemplate;

    pDocTemplate = new CSingleDocTemplate(

        IDR_MAINFRAME,

        RUNTIME_CLASS(CAppFrameDoc),

        RUNTIME_CLASS(CMainFrame), // main SDI frame window

        RUNTIME_CLASS(CAppFrameView));

    AddDocTemplate(pDocTemplate);

#else

    //// MDI 1

    CMultiDocTemplate* pDocTemplate;

    pDocTemplate = new CMultiDocTemplate(

        IDR_MAINFRAME,

        RUNTIME_CLASS(CAppFrameDoc),

        RUNTIME_CLASS(CMainFrame), // custom MDI child frame

        RUNTIME_CLASS(CAppFrameView));

    AddDocTemplate(pDocTemplate);

///////////////////////////

    // create main MDI Frame window

    baseFRAME* pMainFrame = new baseFRAME;

    if (!pMainFrame->LoadFrame(IDR_MAINFRAME))

        return FALSE;

    m_pMainWnd = pMainFrame;

#endif

……..

}

MDI 확장 또는 MDI 추가

MDI에서는 하나의 Document Type에 대해서 Document 여러 개 열 수도 있지만.

다른 Document Type에 대해서도 접근이 가능합니다.

CAppFrameApp::InitInstance()

{

…….

CMultiDocTemplate* pDocTemplate;

pDocTemplate = new CMultiDocTemplate(

        IDR_APPFRATYPE,

        RUNTIME_CLASS(CAppFrameDoc),

        RUNTIME_CLASS(CChildFrame), // custom MDI child frame

        RUNTIME_CLASS(CAppFrameView));

AddDocTemplate(pDocTemplate);

////// DocTemplate 추가

AddDocTemplate(

new CMultiDocTemplate(

        IDR_PARAMETER,

        RUNTIME_CLASS(CParaDoc),

        RUNTIME_CLASS(CFrameParameter), // custom MDI child frame

        RUNTIME_CLASS(CParaView));

);

………….

}

여기서 주의해야 할 것은 DocTemplate이 두 개 이상이므로 Document Type을 구분 할 DocString이 필요하다는 것입니다.

예문에서 IDR_PARAMETER 를 추가 했는데 아래 그림과 같이 "\n"으로 시작하는 String을 만들어 주어야 합니다.

또한 DocTemplate에 추가되는 Document, Child Frame, Child View를 추가 합니다.

이렇게 새로운 Document가 추가 되고 나서 New를 눌러 새로 파일을 생성시키면

와 같이 생성할 Document type을 선택하는 창이 뜹니다.

이전

다음