Multiple-document interface applications will make use of at least one document view pair, but they may also utilise additional documents and views to enable the user to work with more than one document at the same time. Within the client area, each document is displayed within a separate child window. An MDI child window looks much like a typical frame window, except that the MDI child window appears inside an MDI frame window and does not have a menu bar of its own, but instead shares the menu of the MDI frame window. The framework automatically changes the MDI frame menu to represent the currently active MDI child window.
In addition to the 3 classes found in an SDI application, an MDI application must derive a class from CMDIChildWnd which provides the functionality for the Windows multiple document interface (MDI) child window. To make a document different from its parent, the application will also require an additional series of resources other than those associated with the main windows.
As opposed to a Single Document Interface application, a Multiple Document Interface (MDI) application uses the CMultiDocTemplate class which, like the CSingleDocTemplate class, is derived from CdocTemplate.
If the MDI application uses more than one type of document then a separate template must be supplied for each type of document. This will require a separate template for each type of document using a CDocMultiDocTemplate constructor for each.
By default, an SDI or an MDI application, created with the AppWizard will be configured with only a single document class. Additional document class types can however be added by making a second call to AddDocTemplate() in the application class InitInstance() member function as outlined below-
CMultiDocTemplate* pDocTemplate;
PDocTemplate = new CMultiDocTemplate(IDR_SAMPLE1,
RUNTIME_CLASS(CSample1Doc),
RUNTIME_CLASS(CMDIChildWnd),
RUNTIME_CLASS(CSample1View));
AddDocTemplate(pDocTemplate);
pDocTemplate = new CMultiDocTemplate(
IDR_SAMPL2,
RUNTIME_CLASS(CSample2Doc),
RUNTIME_CLASS(CMDIChildWnd),
RUNTIME_CLASS(CSample2View));
AddDocTemplate(pDocTemplate);
The type of document to create can then be selected view the main menu.
The application below allows the user to create a multi document interface base around the CeditView view class
//Must be compiled using a shared DLL
//Microsoft Developer Studio generated resource script.
//
/*
IDR_MDITYPE MENU DISCARDABLE
BEGIN
POPUP "File"
BEGIN
MENUITEM "New", ID_FILE_NEW
MENUITEM "Open", ID_FILE_OPEN
MENUITEM "Close", ID_FILE_CLOSE
MENUITEM "Save", ID_FILE_SAVE
MENUITEM "Save As", ID_FILE_SAVE_AS
MENUITEM "Exit", ID_APP_EXIT
END
POPUP "Edit"
BEGIN
MENUITEM "Undo", ID_EDIT_UNDO
MENUITEM "Cut", ID_EDIT_CUT
MENUITEM "Copy", ID_EDIT_COPY
MENUITEM "Paste", ID_EDIT_PASTE
END
POPUP "Windows"
BEGIN
MENUITEM "windows", ID_WINDOW_NEW
MENUITEM "cascade", ID_WINDOW_CASCADE
MENUITEM "Tile", ID_WINDOW_TILE_HORZ
MENUITEM "Arrange", ID_WINDOW_ARRANGE
END
END
*/
//
#include "resource.h"
#include <afxext.h> // MFC extensions
class CMainFrame : public CMDIFrameWnd
{
DECLARE_DYNAMIC(CMainFrame)
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
DECLARE_MESSAGE_MAP()
};
//child class declaration
class CChildFrame : public CMDIChildWnd
{
DECLARE_DYNCREATE(CChildFrame)
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
DECLARE_MESSAGE_MAP()
};
//application class declaration
class CMDIApp : public CWinApp
{
public:
afx_msg void OnFileNew();
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
//document class declaration
class CMDIDoc : public CDocument
{
protected:
DECLARE_DYNCREATE(CMDIDoc)
public:
virtual BOOL OnNewDocument();
virtual void Serialize(CArchive& ar);
DECLARE_MESSAGE_MAP()
};
//view class declaration
class CMDIView : public CEditView
{
protected:
DECLARE_DYNCREATE(CMDIView)
DECLARE_MESSAGE_MAP()
public:
CMDIDoc* GetDocument();
virtual void OnDraw(CDC* pDC);
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
};
// enable CObject-derived classes to be created dynamically at run time
IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd)
IMPLEMENT_DYNCREATE(CChildFrame, CMDIChildWnd)
IMPLEMENT_DYNCREATE(CMDIDoc, CDocument)
IMPLEMENT_DYNCREATE(CMDIView, CEditView)
//message map frame window
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
ON_WM_CREATE()
END_MESSAGE_MAP()
//message map child window
BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd)
END_MESSAGE_MAP()
//message map application window
BEGIN_MESSAGE_MAP(CMDIApp, CWinApp)
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
END_MESSAGE_MAP()
//message map document window
BEGIN_MESSAGE_MAP(CMDIDoc, CDocument)
END_MESSAGE_MAP()
//message map view window
BEGIN_MESSAGE_MAP(CMDIView, CEditView)
END_MESSAGE_MAP()
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
m_strTitle= "MFC MDI";
if( !CMDIFrameWnd::PreCreateWindow(cs) )
return FALSE;
return TRUE;
}
BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CMDIChildWnd::PreCreateWindow(cs) )
return FALSE;
return TRUE;
}
BOOL CMDIDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
SetTitle ("MDI Window");
return TRUE;
}
void CMDIDoc::Serialize(CArchive& ar)
{
((CEditView*)m_viewList.GetHead())->SerializeRaw(ar);
}
BOOL CMDIView::PreCreateWindow(CREATESTRUCT& cs)
{
BOOL bPreCreated = CEditView::PreCreateWindow(cs);
cs.style &= ~(ES_AUTOHSCROLL|WS_HSCROLL);
return bPreCreated;
}
void CMDIView::OnDraw(CDC* pDC)
{
CMDIDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
}
CMDIDoc* CMDIView::GetDocument()
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMDIDoc)));
return (CMDIDoc*)m_pDocument;
}
BOOL CMDIApp::InitInstance()
{
LoadStdProfileSettings();
//defines a document template that implements the multi document interface
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_MDITYPE,
RUNTIME_CLASS(CMDIDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CMDIView));
CMultiDocTemplate* pDocTemplate1;
pDocTemplate1 = new CMultiDocTemplate(
IDR_MDITYPE,
RUNTIME_CLASS(CMDIDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CMDIView));
AddDocTemplate(pDocTemplate);
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MDITYPE))
return FALSE;
m_pMainWnd = pMainFrame;
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
if (!ProcessShellCommand(cmdInfo))
return FALSE;
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
return TRUE;
}
CMDIApp theApp;
Last Updated: 16 October 2022