먼저 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. 로 변경하는 작업을 해야 합니다.
- 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;
- void CMainFrame::AssertValid() const
{
baseFRAME::AssertValid();
}
- 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이 여러 개 생성 되어 있는 것입니다.
지문이 너무 길어져서 다음에 설명 하기로 합니다.
'개발언어 > c++' 카테고리의 다른 글
MDI(Multi Document Interface)로 개발하기4 (0) | 2016.07.25 |
---|---|
MDI(Multi Document Interface)로 개발하기 3 (0) | 2016.07.19 |
MDI(Multi Document Interface)로 개발하기1 (0) | 2016.07.18 |
LNK2005 _DllGetClassObjec,already defined in AtlTest.obj (0) | 2016.07.18 |
error LNK2001: unresolved external symbol _main (0) | 2016.07.18 |