티스토리 뷰
MFC MDI (Multiple Document Interface)
하나의 응용 프로그램에서 동시에 2개 이상의 도큐먼트를 대상으로 작업할 수 있는 사용자 인터페이스
SDI 설명 참조 (http://petra.tistory.com/949)
기본 구조는 응용프로그램, 도큐먼트 템플릿(CMultiDocTemplate), 메인 윈도우(CMDIFrameWnd) 객체는 항상 존재하고,
도큐먼트(CDocument), 도큐먼트 프레임 윈도우(CMDIChildWnd), 뷰 객체는 새로운 문서를 작성하거나 저장된 문서를 열때마다 새로 생성된다.
<SDI 와 차이점>
1. 도큐먼트 템플릿으로 CSingleDocTemplate 클래스 대신 CMultiDocTemplate 클래스를 사용한다.
2. SDI 응용 프로그램과 달리 MDI 응용 프로그램은 도큐먼트 객체를 재사용하지 않고 매번 새로 생성한다.
3. SDI 응용 프로그램에서는 메인 윈도우와 도큐먼트 프레임 윈도우가 동일하므로 줄여서 프레임 윈도우라는 용어를 사용하였다. 그러나 MDI 응용 프로그램에서는 메인 윈도우와 도큐먼트 프레임 윈도우가 별개이며 각각 CMDIFrameWnd, CMDIChildWnd 클래스를 사용한다.
<MDI 메뉴 2가지>
1. IDR_MAINFRAME : 열린 문서(창)가 없을때 나타나는 메뉴
2. IDR_MDISQUTTYPE : 1개 이상의 문서가 열릴때 표시되는 메뉴
MDI 프로젝트를 만들면
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 |
BOOL CMFCApplication13App::InitInstance()
{
...
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_MFCApplication1TYPE,
RUNTIME_CLASS(CMFCApplication13Doc),
RUNTIME_CLASS(CChildFrame), // 사용자 지정 MDI 자식 프레임입니다.
RUNTIME_CLASS(CMFCApplication13View));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
// 주 MDI 프레임 창을 만듭니다.
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
{
delete pMainFrame;
return FALSE;
}
m_pMainWnd = pMainFrame;
} |
cs |
SDI 응용 프로그램과 달리 메인 윈도우(CMainFrame) 객체는 new 연산자를 이용하여 따로 생성한다.
도큐먼트, 도큐먼트 프레임 윈도우, 뷰 클래스의 정보는 도큐먼트 템플릿 객체에 저장해 두었다가 필요할 때마다 이 정보를 토대로 객체를 생성하게 된다.
CMDIChildWnd* CMDIFrameWnd::MDIGetActive(BOOL* pbMaximized=NULL);
CFrameWnd* CFrameWnd::GetActiveFrame();
두 함수 모두 활성 도큐먼트 프레임 윈도우 객체의 주소를 리턴한다. MDI 응용 프로그램에는 여러개의 도큐먼트 프레임 윈도우가 존재할 수 있으나 현재 사용자가 작업하고 있는 활성 뷰를 감싸고 있는 도큐먼트 프레임 윈도우는 오직 1개다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 |
class CMFCApplication13Doc : public CDocument
{
...
public:
CString m_str;
};
BOOL CMFCApplication13Doc::OnNewDocument()
{
...
m_str = L"";
return TRUE;
}
void CMFCApplication13Doc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_str;
}
else
{
ar >> m_str;
}
}
BEGIN_MESSAGE_MAP(CMFCApplication13View, CView)
...
ON_WM_CHAR()
END_MESSAGE_MAP()
void CMFCApplication13View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CMFCApplication13Doc* pDoc = GetDocument();
pDoc->m_str.AppendChar(nChar);
pDoc->SetModifiedFlag();
pDoc->UpdateAllViews(NULL);
CView::OnChar(nChar, nRepCnt, nFlags);
} |
cs |
창 메뉴 안에서 새창 메뉴를 산택하면 뷰가 추가 생성되는데 이때 1개의 도큐먼트에 2개의 뷰가 존재하게 된다. (새창 메뉴를 선택한 만큼 뷰가 생성)
파일 - 새파일 메뉴를 선택하거나 새로 만들기 툴바를 클릭하면 새로운 도큐먼트와 도큐먼트 프레임 윈도우, 뷰 객체가 생성된다.
아래 그림과 같이 CDrawDoc, CDrawView 클래스 추가한다.
아래 그림과 같이 아이콘, 메뉴, 문자열 리소스 추가한다. (IDR_DRAWTYPE 으로 통일 시킴)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 |
#include "DrawDoc.h"
#include "DrawView.h"
BOOL CMFCApplication13App::InitInstance()
{
...
pDocTemplate = new CMultiDocTemplate(IDR_DRAWTYPE,
RUNTIME_CLASS(CDrawDoc),
RUNTIME_CLASS(CChildFrame), // 사용자 지정 MDI 자식 프레임입니다.
RUNTIME_CLASS(CDrawView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
}
BEGIN_MESSAGE_MAP(CDrawView, CView)
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
CClientDC dc(this);
dc.SelectStockObject(LTGRAY_BRUSH);
dc.Rectangle(point.x - 20, point.y - 20, point.x + 20, point.y + 20);
CView::OnLButtonDown(nFlags, point);
}
|
cs |
프로그램 실행하면 위 그림처럼 새로만들기 선택 창이 뜬다.
MFCApplication1 을 선택하면 위 그림처럼 키 입력을 받아 출력하는 뷰가 생성되고,
Draw를 선택하면 아래 그림처럼 사각형을 그리는 뷰가 생성된다.
MDI 에서 모든 자식창 닫기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 |
CView* pView;
CDocument* pDoc;
CChildFrame* pChildFrame;
CDocTemplate *pDocTemp;
POSITION posDoc, posView, posTemp = theApp.GetFirstDocTemplatePosition();
while (posTemp != NULL)
{
pDocTemp = theApp.GetNextDocTemplate(posTemp);
posDoc = pDocTemp->GetFirstDocPosition();
while (posDoc != NULL)
{
pDoc = pDocTemp->GetNextDoc(posDoc);
posView = pDoc->GetFirstViewPosition();
while (posView != NULL)
{
pView = pDoc->GetNextView(posView);
pChildFrame = (CChildFrame*)pView->GetParentFrame();
pChildFrame->창닫기();
}
}
}
void CChildFrame::창닫기()
{
// TODO: 여기에 구현 코드 추가.
CMDIChildWndEx::OnClose();
} |
cs |
MDI 관련 블로그들