메뉴 닫기

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

먼저 Formview를 수정하여 화면에 출력 할 수 있도록 ID를 수정하자

“AppFrame.h”를 수정하여 붉은색으로 표시된 부분과 같이 추가하자.

 

#include <afxtempl.h> // 추가

class CAppFrameApp : public CWinApp

{

public:

struct st_view //윈도우 개수를 정하기 위한 구조체

    {

        UINT max;

        UINT sz;

    };

    CMap<CString,LPCSTR,st_view*,st_view*> m_arDoc;//

CAppFrameApp();

………………..

DECLARE_MESSAGE_MAP()

protected:

void CreateView();

};

“AppFrame.cpp”부분을 수정하여 윈도우를 새로 생성하는 부분을 만들어 보자.

CAppFrameApp::CAppFrameApp()

{

// TODO: add construction code here,

// Place all significant initialization in InitInstance

st_view* p_view=NULL;

m_arDoc.SetAt(“AppFrame”,new st_view);

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

// 각각의 DOC Type에 대한 윈도우 갯수

p_view=m_arDoc[“AppFrame”];

p_view->max=4;

p_view->sz=0;

}

BOOL CAppFrameApp::InitInstance()

{

AfxEnableControlContainer();

………………

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CAppFrameDoc),

RUNTIME_CLASS(CMainFrame), // main SDI frame window

RUNTIME_CLASS(CAppFrameView));

AddDocTemplate(pDocTemplate);

// Parse command line for standard shell commands, DDE, file open

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

// Dispatch commands specified on the command line

if (!ProcessShellCommand(cmdInfo))

return FALSE;

CreateView();//FileNew 이전에 View를 생성하기

// The one and only window has been initialized, so show and update it.

m_pMainWnd->ShowWindow(SW_SHOW);

m_pMainWnd->UpdateWindow();

return TRUE;

}

//View를 임의로 만들기

void CAppFrameApp::CreateView()

{

UINT nID=IDD_APPFRAME_FORM;

POSITION pos =NULL;

CRect mRect;

CView* pNewView = NULL;

CString m_Fmt;

CRuntimeClass *pNewViewClass=RUNTIME_CLASS(CAppFrameView);

CView* pOldView = ((CFrameWnd*)m_pMainWnd)->GetActiveView();//View 이미 생성되어 있음

CDocument* pDoc = ((CFrameWnd*)m_pMainWnd)->GetActiveDocument();

st_view* p_view=m_arDoc[“AppFra”];//창의 최대 개수와 생성된 개수 지정되어 있음

m_Fmt.Format(“Window %d”,p_view->sz);

If(pOldView)

    pOldView->GetClientRect(&mRect);

mRect.top+=130;

mRect.right=200;

mRect.bottom-=10;

pOldView->MoveWindow(mRect);

pOldView->SetDlgItemText(IDC_STATIC_CNT,m_Fmt);

for(p_view->sz=1;p_view->sz<p_view->max;p_view->sz++)

{

    CCreateContext context;

    context.m_pCurrentDoc = pDoc;

m_Fmt.Format(“Window %d”,p_view->sz);

    pNewView = (CView*)pNewViewClass->CreateObject();

    pNewView->Create(NULL, NULL, 0,

    mRect/*CFrameWnd::rectDefault*/,

m_pMainWnd, nID, &context);

pNewView->OnInitialUpdate();

pNewView->SetDlgItemText(IDC_STATIC_CNT,m_Fmt);

pNewView->ShowWindow(SW_SHOW);

mRect.OffsetRect(mRect.Width(),0);

}

}

F5를 눌러 실행시켜보면 그림과 같은 화면이 보입니다다.

그리고 하나의 View만 정상적으로 활성화(Active) 되어 있는 것을 볼 수 있을 것입니다.

SDI에 대해서는 자세한 설명을 하지 않겠습니다.

대략 적으로 둘러 볼 내용은 SDI는 하나의 Document에 접근하고 IDR_MAINFRAME 및 CMainFrame, CAppFrameView 및 Document가 하나의 그룹으로 이루어져 있고 하나의 View만

Active되 어 사용된다고 이해 만 하고 지나 가겠습니다.


자 이제 지금까지 코딩 한 것을 MDI로 만들고 특징을 분석해 보기로 합니다.

먼저 현재 까지 작업한 내용 중 몇 군데를 수정 하겠습니다.

“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 이 CFrameWnd 또는 CMDIFrameWnd 둘 중 어느 하나를 상속받게 만든 것 입니다.

필요에 따라 //#define FRAME_SDI 를 주석으로 처리하면 MDI가 되고 주석을 없애면 SDI가 되도록 구성한 것입니다.

CMainFrame 는 SDI일 때 CFrameWnd 를 MDI일 때 는 CMDIFrameWnd 상속 받기 때문 입니다.

class CMainFrame : public baseFRAME

{

…..

}

컴파일 해보면 “MainFrame.cpp” 부분에 다수의 에러를 발견하게 될 텐데

CFrameWnd-> baseFRAME. 로 변경하는 작업을 해야 합니다.

  1. IMPLEMENT_DYNCREATE(CMainFrame, baseFRAME)
  2. BE
    GIN_MESSAGE_MAP(CMainFrame, baseFRAME)
  1. int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

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

return -1;

  1. BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

if( !baseFRAME::PreCreateWindow(cs) )

return FALSE;

  1. void CMainFrame::AssertValid() const

{

baseFRAME::AssertValid();

}

  1. void CMainFrame::Dump(CDumpContext& dc) const

{

baseFRAME::Dump(dc);

}

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

MDI로 전환 시킵니다.

LoadStdProfileSettings(); // Load standard INI file options (including MRU)

// Register the application’s document templates. Document templates

// serve as the connection between documents, frame windows and views.

#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

// Parse command line for standard shell commands, DDE, file open

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

// Dispatch commands specified on the command line

if (!ProcessShellCommand(cmdInfo))

return FALSE;

그리고 다시 실행 시켜봅니다.아직 정상동작이 되지 않을 것입니다.

void CAppFrameApp::CreateView()부분을 디버깅 해보면

CView* pOldView = ((CFrameWnd*)m_pMainWnd)->GetActiveView(); 부터 에러가 발생 되는 것을 볼 수 있을 것입니다.

이하 부분

for(p_view->sz=1;p_view->sz<p_view->max;p_view->sz++)

{

    CCreateContext context;

    context.m_pCurrentDoc = pDoc;

m_Fmt.Format(“Window %d”,p_view->sz);

    pNewView = (CView*)pNewViewClass->CreateObject();

…….

}

에서 정상 실행이 되었는데도 아무런 창이 뜨지 않는 것을 확인 할 수 있을 것 입니다.

CAppFrameApp::InitInstance() 의 아래 부분에서 CreateView(); 부분은 SDI에서도 별다른

역할을 하지 못하고 MDI에서도 정상 동작 하지 않으므로 MDI에서만 동작 하도록 변경하고.

#ifndef FRAME_SDI //MDI일때만

CreateView();//FileNew 이전에 View를 생성하기

#endif

CreateView()를 수정합니다.

void CAppFrameApp::CreateView()

{

    CString strDocName;

    CDocTemplate* pSelect=NULL;

    st_view* p_view=NULL;

    POSITION pos=GetFirstDocTemplatePosition();

    while(pos!=NULL)

    {

        pSelect=GetNextDocTemplate(pos);

        pSelect->GetDocString(strDocName,CDocTemplate::docName);

        pSelect->SaveAllModified();

        if(!strDocName.IsEmpty())

        {

         p_view=m_arDoc[strDocName];

         if(p_view)

         {

         for(p_view->sz=0;p_view->sz<p_view->max;p_view->sz++)//미리 정의 해둔 갯수 만큼 윈도우 만들기

            {

             pSelect->OpenDocumentFile(NULL);

            }

         }

        }

    }

}

일단 한번 실행시켜보면 pSelect->GetDocString(strDocName,CDocTemplate::docName);

에서 Doc Type 을 가져오지 못하는 것을 볼 수 있습니다.

이 문제의 비밀은

String Table의 IDR_MAINFRAME 과 관계가 있습니다.

SDI 일 때 IDR_MAINFRAME 의 내용


MDI 차이를 보이는 것을 알 수 있습니다. 이는 MDI에서 여러 개의 Document Type에 접근 할 때 문서의 확장자를 결정하는 중요한 요소가 됩니다.

MDI형태로 String Table의 내용을 변경하고 일단 한번 구동 시켜 봅니다.

여러 개의 창이 생성된 것을 볼 수 있습니다. 정확히 말하면 View가 없이 MainFrame이 여러 개 생성 되어 있는 것입니다.


지문이 너무 길어져서 다음에 설명 하기로 합니다.

다음

이전글

댓글 남기기

이메일은 공개되지 않습니다.