设计思路:
文档负责保存数据对象,没有个数据对象(特征对象,如三通管)包含3种显示:三维示例图,二维展开图和计算文档,初步设计通过定义不同的视图来表示不同的显示,现在的问题是如何实现?
该功能已经实现!
通过创建文档模板的方式,将所要添加的视图类信息添加进来,
关键代码如下:
<code begin>
class CIntraGlDocTemplate : public CSingleDocTemplate
{
DECLARE_DYNAMIC(CIntraGlDocTemplate)
// Constructors
public:
CIntraGlDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass,
CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass,
int nSplitterID = -1, int nRow = 0, int nCol = 0);
// Attributes
public:
int m_nSplitterID; // -1, no splitter else splitter ID (0, 1,...)
int m_nRow; // if splitter, row number (0, 1,...)
int m_nCol; // if splitter, col number (0, 1,...)
CView* m_pView; // view pointer
// these overrides to retreive the view class and resource ID
CRuntimeClass* GetViewClass()
{ return m_pViewClass; }
UINT GetResourceID()
{ return m_nIDResource; }
};
//
IMPLEMENT_DYNAMIC(CIntraGlDocTemplate, CSingleDocTemplate)
CIntraGlDocTemplate::CIntraGlDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass,
CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass,
int nSplitterID, int nRow, int nCol) :
CSingleDocTemplate(nIDResource, pDocClass, pFrameClass, pViewClass)
{
m_nSplitterID = nSplitterID;
m_nRow = nRow;
m_nCol = nCol;
m_pView = NULL;
}
///app类的instance函数如下
BOOL CIntraGlApp::InitInstance()
{
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// Change the registry key under which our settings are stored.
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
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.
CIntraGlDocTemplate* pDocTemplate;
pDocTemplate = new CIntraGlDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CIntraGlDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CModelView));
AddDocTemplate(pDocTemplate);
//CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CIntraGlDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CIntraGlDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CDrawingView));
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;
// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}
// add the following member function to the CMainFram class
class CSplitInfo
{
public:
int m_MaxRow, m_MaxCol;
CSplitterWnd m_wndSplitter;
CSplitInfo::CSplitInfo();
CSplitInfo &operator=(const CSplitInfo &SplitInfo);
};
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,CCreateContext* pContext)
{
CView* pView;
CIntraGlApp* pApp = (CIntraGlApp*)AfxGetApp();
ASSERT_KINDOF(CIntraGlApp, pApp);
// hold informations from DocTemplates to create splitter
POSITION TmpPos = pApp->GetFirstDocTemplatePosition();
while (TmpPos)
{
CIntraGlDocTemplate* pTemplate = (CIntraGlDocTemplate*)pApp->GetNextDocTemplate(TmpPos);
ASSERT_KINDOF(CIntraGlDocTemplate, pTemplate);
if (pTemplate->m_nSplitterID != -1)
{
// find or create the splitter ID in the splitter map
int nID = pTemplate->m_nSplitterID;
m_SplitInfo[nID].m_MaxRow = max(m_SplitInfo[nID].m_MaxRow, pTemplate->m_nRow + 1);
m_SplitInfo[nID].m_MaxCol = max(m_SplitInfo[nID].m_MaxCol, pTemplate->m_nCol + 1);
}
}
// create the splitter and the views in the splitter
POSITION MapPos = m_SplitInfo.GetStartPosition();
while (MapPos)
{
int nID; CSplitInfo SplitInfo;
m_SplitInfo.GetNextAssoc(MapPos, nID, SplitInfo);
if (m_SplitInfo[nID].m_MaxRow && m_SplitInfo[nID].m_MaxCol)
{
CRect rect; GetClientRect(&rect);
int cx = rect.Width(); int cy = rect.Height();
// normaly always ToolBar & StatusBar
cy = cy - 56; if (cy < 56) cy = 0;
if (m_SplitInfo[nID].m_MaxCol) cx /= m_SplitInfo[nID].m_MaxCol;
if (m_SplitInfo[nID].m_MaxRow) cy /= m_SplitInfo[nID].m_MaxRow;
CSize sizeDefault(cx, cy);
m_SplitInfo[nID].m_wndSplitter.CreateStatic(this, m_SplitInfo[nID].m_MaxRow, m_SplitInfo[nID].m_MaxCol);
// disable view ID to use for next splitter
m_SplitInfo[nID].m_wndSplitter.SetDlgCtrlID(0);
TmpPos = pApp->GetFirstDocTemplatePosition();
while (TmpPos)
{
CIntraGlDocTemplate* pTemplate = (CIntraGlDocTemplate*)pApp->GetNextDocTemplate(TmpPos);
if (pTemplate->m_nSplitterID == nID)
{
// create view
int nRow = pTemplate->m_nRow, nCol = pTemplate->m_nCol;
pContext->m_pNewDocTemplate = pTemplate;
pContext->m_pNewViewClass = pTemplate->GetViewClass();
if (!m_SplitInfo[nID].m_wndSplitter.CreateView(nRow, nCol,
pContext->m_pNewViewClass, sizeDefault, pContext)) return FALSE;
pTemplate->m_pView = (CView*)m_SplitInfo[nID].m_wndSplitter.GetPane(nRow, nCol);
}
}
// disable view ID to use for next splitter view
TmpPos = pApp->GetFirstDocTemplatePosition();
while (TmpPos)
{
CIntraGlDocTemplate* pTemplate = (CIntraGlDocTemplate*)pApp->GetNextDocTemplate(TmpPos);
if (pTemplate->m_nSplitterID == nID)
pTemplate->m_pView->SetDlgCtrlID(0);
}
}
}
// create the other views (no splitter)
TmpPos = pApp->GetFirstDocTemplatePosition();
while (TmpPos)
{
CIntraGlDocTemplate* pTemplate = (CIntraGlDocTemplate*)pApp->GetNextDocTemplate(TmpPos);
if (pTemplate->m_nSplitterID == -1)
{
pContext->m_pNewViewClass = pTemplate->GetViewClass();
pView = (CView*)CreateView(pContext, AFX_IDW_PANE_FIRST);
ASSERT(pView != NULL);
pTemplate->m_pView = pView;
// disable view ID to use for next view
pView->SetDlgCtrlID(0);
}
}
SetActiveView(NULL);
CIntraGlDocTemplate *pTemplate;
// litle problem ! if a CRichEditView is in the view list
// we must activate it first to update the layout correctly
pTemplate = pApp->GetTemplate(RUNTIME_CLASS(CModelView));
if (pTemplate) ActivateView(pTemplate->GetViewClass());
// activate the first doctemplate view
pTemplate = pApp->GetFirstTemplate();
ActivateView(pTemplate->GetViewClass());
return TRUE;
}
void CMainFrame::ActivateView(CRuntimeClass* pViewClass)
{
CIntraGlApp* pApp = (CIntraGlApp*)AfxGetApp();
CView* pActiveView = GetActiveView();
CIntraGlDocTemplate* pNewTemplate = pApp->GetTemplate(pViewClass);
CIntraGlDocTemplate* pActiveTemplate = pApp->GetTemplate(pActiveView);
// the view class doesn't exist
if (pNewTemplate == NULL) return;
// the new template is the active template, do nothing
if (pNewTemplate == pActiveTemplate) return;
// the active and new template are in the same splitter, change the active view
if (pActiveTemplate != NULL)
{
if (pActiveTemplate->m_nSplitterID != -1 &&
pActiveTemplate->m_nSplitterID == pNewTemplate->m_nSplitterID)
{
UpdateResource(pNewTemplate);
SetActiveView(pNewTemplate->m_pView);
return;
}
// the active view is in a splitter, hide all views in the splitter and the splitter
if (pActiveTemplate->m_nSplitterID != -1)
{
POSITION TmpPos;
CIntraGlDocTemplate* pTemplate;
int nID = pActiveTemplate->m_nSplitterID;
TmpPos = pApp->GetFirstDocTemplatePosition();
while (TmpPos)
{
pTemplate = (CIntraGlDocTemplate*)pApp->GetNextDocTemplate(TmpPos);
if (pTemplate->m_nSplitterID == nID)
{
pTemplate->m_pView->ShowWindow(SW_HIDE);
pTemplate->m_pView->SetDlgCtrlID(0);
}
}
// hide the splitter
m_SplitInfo[nID].m_wndSplitter.SetDlgCtrlID(0);
m_SplitInfo[nID].m_wndSplitter.ShowWindow(SW_HIDE);
}
// the active view is not in a splitter, hide this view
else
{
pActiveTemplate->m_pView->SetDlgCtrlID(0);
pActiveTemplate->m_pView->ShowWindow(SW_HIDE);
}
}
// the new view is in a splitter, show all splitter views and the splitter
if (pNewTemplate->m_nSplitterID != -1)
{
POSITION TmpPos;
CIntraGlDocTemplate* pTemplate;
int nID = pNewTemplate->m_nSplitterID;
TmpPos = pApp->GetFirstDocTemplatePosition();
while (TmpPos)
{
pTemplate = (CIntraGlDocTemplate*)pApp->GetNextDocTemplate(TmpPos);
if (pTemplate->m_nSplitterID == nID)
{
int nRow = pTemplate->m_nRow;
int nCol = pTemplate->m_nCol;
int nDlgID = m_SplitInfo[nID].m_wndSplitter.IdFromRowCol(nRow, nCol);
pTemplate->m_pView->SetDlgCtrlID(nDlgID);
pTemplate->m_pView->ShowWindow(SW_SHOW);
}
}
// show the splitter
m_SplitInfo[nID].m_wndSplitter.SetDlgCtrlID(AFX_IDW_PANE_FIRST);
m_SplitInfo[nID].m_wndSplitter.ShowWindow(SW_SHOW);
}
// the new view is not in a splitter, active the new view
else
{
pNewTemplate->m_pView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
pNewTemplate->m_pView->ShowWindow(SW_SHOW);
}
UpdateResource(pNewTemplate);
// display and update the new view
SetActiveView(pNewTemplate->m_pView);
RecalcLayout();
}
BOOL CMainFrame::IsViewActive(CRuntimeClass* pViewClass)
{
CView* pActiveView = GetActiveView();
if (pActiveView == NULL) return FALSE;
return (pActiveView->GetRuntimeClass() == pViewClass);
}
void CMainFrame::UpdateResource(CIntraGlDocTemplate *pNewTemplate)
{
CIntraGlApp* pApp = (CIntraGlApp*)AfxGetApp();
// support for view context menu, accelerator and help ID like MDI
HINSTANCE hInst = AfxFindResourceHandle(MAKEINTRESOURCE(pNewTemplate->GetResourceID()), RT_MENU);
// if menu is not the default menu, destroy it
HMENU hMenu = ::GetMenu(m_hWnd);
if (hMenu != m_hMenuDefault) ::DestroyMenu(hMenu);
// load menu from doctemplate
hMenu = ::LoadMenu(hInst, MAKEINTRESOURCE(pNewTemplate->GetResourceID()));
// if no menu, get default
if (hMenu == NULL) hMenu = m_hMenuDefault;
// load menu
::SetMenu(m_hWnd, hMenu);
// load new accelerator table
HACCEL hAccel = ::LoadAccelerators(hInst, MAKEINTRESOURCE(pNewTemplate->GetResourceID()));
// if no table for this template, load default
if (hAccel == NULL) ::LoadAccelerators(hInst, MAKEINTRESOURCE(pApp->GetFirstTemplate()->GetResourceID()));
// chage help ID for this view
m_nIDHelp = pNewTemplate->GetResourceID();
// change the title of the document
pNewTemplate->GetDocString(m_strTitle, CDocTemplate::windowTitle);
OnUpdateFrameTitle(TRUE);
}
// the command notification function is
void CMainFrame::OnViewModel()
{
// TODO: Add your command handler code here
ActivateView(RUNTIME_CLASS(CModelView));
}
void CMainFrame::OnUpdateViewModel(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->SetCheck(IsViewActive(RUNTIME_CLASS(CModelView)));
}
<code end>
if you need the source code please email to me. hongxian.qin@autodesk.com
created by HongxianQin