MFC SDI单文档多视图的实现及自由切换
结合网上学习总结别人的例子,以及参考MSDN给出的例子,对SDI多视图的实现进行了一个简单的总结,以记录学习点滴.
首先在H文件有如下声明:
class CMultiViewApp : public CWinApp
{
public:
CView* m_pFirstView;
CView* m_pOtherView;
int m_currentView;
CView* m_pView2;
CView* m_pView1;
CMultiViewApp();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMultiViewApp)
public:
virtual BOOL InitInstance();
//}}AFX_VIRTUAL
// Implementation
//{{AFX_MSG(CMultiViewApp)
afx_msg void OnAppAbout();
afx_msg void OnViewOtherview();
afx_msg void OnViewFirstview();
//}}AFX_MSG
afx_msg void OnViewChange(UINT nCmdID);
DECLARE_MESSAGE_MAP()
};
其次,在CPP文件有如下消息MAP:
/
// CMultiViewApp
BEGIN_MESSAGE_MAP(CMultiViewApp, CWinApp)
//{{AFX_MSG_MAP(CMultiViewApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
ON_COMMAND(ID_VIEW_OTHERVIEW, OnViewOtherview)
ON_COMMAND(ID_VIEW_FIRSTVIEW, OnViewFirstview)
//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
ON_COMMAND_RANGE( ID_VIEW_VIEW1, ID_VIEW_VIEW2, OnViewChange)
END_MESSAGE_MAP()
说明:SDI程序在CMyApp::InitInstance()已经通过DocTemplate创建一个关联的视图/文档实例,切显示出来.具体实现如下:
BOOL CMultiViewApp::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.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CMultiViewDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CMultiViewView));
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;
CView* pActiveView = ((CFrameWnd*) m_pMainWnd)->GetActiveView();
m_pFirstView = pActiveView;
m_pOtherView = (CView*) new COtherView;
CDocument* pDoc = ((CFrameWnd*)m_pMainWnd)->GetActiveDocument();
//通过CCreateContext实现第二视图和文档的关联
CCreateContext context;
context.m_pCurrentDoc = pDoc;
UINT m_ID = AFX_IDW_PANE_FIRST + 1;
CRect rect;
//为了演示第一种多视图是实现方法,把Vew的实例创建放在了这里
m_pOtherView->Create(NULL, NULL, WS_CHILD, rect, m_pMainWnd, m_ID, &context);
// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
m_pMainWnd->UpdateWindow();
m_currentView=1;
return TRUE;
}
1. SDI单文档多视图实现方法1
void CMultiViewApp::OnViewOtherview()
{
// TODO: Add your command handler code here
UINT temp = ::GetWindowLong(m_pOtherView->m_hWnd, GWL_ID);
::SetWindowLong(m_pOtherView->m_hWnd, GWL_ID, ::GetWindowLong(m_pFirstView->m_hWnd, GWL_ID));
::SetWindowLong(m_pFirstView->m_hWnd, GWL_ID, temp);
m_pFirstView->ShowWindow(SW_HIDE);
m_pOtherView->ShowWindow(SW_SHOW);
((CFrameWnd*)m_pMainWnd)->SetActiveView(m_pOtherView);
((CFrameWnd*) m_pMainWnd)->RecalcLayout();
m_pOtherView->Invalidate();
}
void CMultiViewApp::OnViewFirstview()
{
// TODO: Add your command handler code here
UINT temp = ::GetWindowLong(m_pOtherView->m_hWnd, GWL_ID); //GetWindowWord()
::SetWindowLong(m_pOtherView->m_hWnd, GWL_ID, ::GetWindowLong(m_pFirstView->m_hWnd, GWL_ID));//SetWindowWord()
::SetWindowLong(m_pFirstView->m_hWnd, GWL_ID, temp);//SetWindowWord()
m_pOtherView->ShowWindow(SW_HIDE);
m_pFirstView->ShowWindow(SW_SHOW);
((CFrameWnd*)m_pMainWnd)->SetActiveView(m_pFirstView);
((CFrameWnd*)m_pMainWnd)->RecalcLayout();
m_pFirstView->Invalidate();
}
2. SDI单文档多视图实现方法2
void CMultiViewApp::OnViewChange(UINT nCmdID)
{
//另外一种方法实现SDI的多视图切换
CView* pViewAdd;
CView* pViewRemove;
CMainFrame* pMainFrame=(CMainFrame*)AfxGetMainWnd();
CDocument* pDoc = pMainFrame->GetActiveDocument();
if((nCmdID == ID_VIEW_VIEW1) && (m_currentView == 1))
return;
if((nCmdID == ID_VIEW_VIEW2) && (m_currentView == 2))
return;
if (nCmdID == ID_VIEW_VIEW2)
{
if (m_pView2 == NULL)
{
m_pView1 = pMainFrame->GetActiveView();
m_pView2 = new COtherView();
//Note that if OnSize has been overridden in CMyView2
//and GetDocument() is used in this override it can
//cause assertions and, if the assertions are ignored,
//cause access violation.
//使用CCreateContext structure实现view和document的关联
CCreateContext context;
context.m_pCurrentDoc=pDoc;//m_pView1->GetDocument();
m_pView2->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CFrameWnd::rectDefault, AfxGetMainWnd(), AFX_IDW_PANE_FIRST + 1, &context/*NULL*/);
}
pViewAdd = m_pView2;
pViewRemove = m_pView1;
m_currentView= 2;
}
else
{
pViewAdd = m_pView1;
pViewRemove = m_pView2;
m_currentView= 1;
}
// Set the child i.d. of the active view to AFX_IDW_PANE_FIRST,
// so that CFrameWnd::RecalcLayout will allocate to this
// "first pane" that portion of the frame window's client area
// not allocated to control bars. Set the child i.d. of the
// other view to anything other than AFX_IDW_PANE_FIRST; this
// examples switches the child id's of the two views.
int nSwitchChildID = pViewAdd->GetDlgCtrlID();
pViewAdd->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
pViewRemove->SetDlgCtrlID(nSwitchChildID);
// Show the newly active view and hide the inactive view.
pViewAdd->ShowWindow(SW_SHOW);
pViewRemove->ShowWindow(SW_HIDE);
// Connect the newly active view to the document, and
// disconnect the inactive view.
//通过CCreateContext实现视图View和文档Document的关联
//就没有必要手动AddView(),如果需要可以进行手动RemoveView()
//AddView()会在CView::OnCreate()被MFC调用,RemoveView()会在CView::~CView()被调用
//当然可以根据需要手动调用它们,在本例当中,View都是被创建一次,没有被销毁,所以不会自动
//调用RemoveView()
//pDoc->AddView(pViewAdd);
//pDoc->RemoveView(pViewRemove);
pMainFrame->SetActiveView(pViewAdd);
pMainFrame->RecalcLayout();
return ;
}