- 源文件下载链接
- 最后界面
- 创建单文档exe支持切分窗口
- 新建对话框资源
- 新建视图类并添加控件型变量和初始化函数
- 创建一个切分窗口类
- 其实质是在切分窗口添加编辑视图和列表视图对象
- 创建右侧切分窗口的框架类
- 左面版添加视图类成员变量
- 修改MainFrame创建静态切分窗口
源文件下载链接
最后界面
1、创建单文档exe,支持切分窗口。
2、新建对话框资源
ID为IDD_TREEVIEW,Style=CHILD,BORDER=NONE,
删掉按钮OK和CANCEL,添加Tree控件IDC_TREE,占满整个对话框
导入位图资源,ID为IDB_BITMAP
新建列表对话框IDD_LISTCTRLVIEW,Style=CHILD,BORDER=NONE,
添加LISTCONTROL控件IDC_LIST,占满蓝色边框,
和编辑视图的对话框资源IDD_EDITVIEW,Style=CHILD,BORDER=NONE,删掉上面的按钮。
添加EditBox控件IDC_EDIT,占满蓝色边界线
3、新建视图类并添加控件型变量和初始化函数
建立2 个View 的类,这里我们让这2个View 的类继承于FormView,
CListControlView 继承于FormView 关联对话框 IDD_LISTVIEW,为了后面可以new 将构造函数改为publlic属性(默认为protected)
- class CListControlView : public CFormView
- {
- public:
- CListControlView(); // protected constructor used by dynamic creation
- DECLARE_DYNCREATE(CListControlView)
class CListControlView : public CFormView
{
public:
CListControlView(); // protected constructor used by dynamic creation
DECLARE_DYNCREATE(CListControlView)
- };
};
为列边框添加控件类型变量m_listCtrl
为对话框添加OnSize消息,使列表框与对话框等大
- void CListControlView::OnSize(UINT nType, int cx, int cy)
- {
- CFormView::OnSize(nType, cx, cy);
- // TODO: Add your message handler code here
- CFormView::ShowScrollBar(SB_VERT,FALSE);
- CFormView::ShowScrollBar(SB_HORZ,FALSE);
- if (GetSafeHwnd())
- {
- if (m_listCtrl.GetSafeHwnd())
- {
- CRect rect(0,0,cx,cy);
- m_listCtrl.MoveWindow(&rect);
- }
- }
- }
void CListControlView::OnSize(UINT nType, int cx, int cy)
{
CFormView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
CFormView::ShowScrollBar(SB_VERT,FALSE);
CFormView::ShowScrollBar(SB_HORZ,FALSE);
if (GetSafeHwnd())
{
if (m_listCtrl.GetSafeHwnd())
{
CRect rect(0,0,cx,cy);
m_listCtrl.MoveWindow(&rect);
}
}
}
添加虚函数,初始化列表框
- void CListControlView::OnInitialUpdate()
- {
- CFormView::OnInitialUpdate();
- // TODO: Add your specialized code here and/or call the base class
- CRect rect;
- m_listCtrl.GetClientRect(&rect);
- m_listCtrl.InsertColumn(0, "From", LVCFMT_LEFT, rect.Width()/4);
- m_listCtrl.InsertColumn(1, "Subject", LVCFMT_LEFT, rect.Width()/4);
- m_listCtrl.InsertColumn(2, "Date", LVCFMT_LEFT, rect.Width()/4);
- m_listCtrl.InsertColumn(3, "Size", LVCFMT_LEFT, rect.Width()/4);
- }
void CListControlView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
CRect rect;
m_listCtrl.GetClientRect(&rect);
m_listCtrl.InsertColumn(0, "From", LVCFMT_LEFT, rect.Width()/4);
m_listCtrl.InsertColumn(1, "Subject", LVCFMT_LEFT, rect.Width()/4);
m_listCtrl.InsertColumn(2, "Date", LVCFMT_LEFT, rect.Width()/4);
m_listCtrl.InsertColumn(3, "Size", LVCFMT_LEFT, rect.Width()/4);
}
CEditControlView 继承于FormView 关联对话框IDD_EDITVIEW,为了后面可以new 将构造函数改为publlic属性(默认为protected)
- class CEditControlView : public CFormView
- {
- public:
- CEditControlView(); // protected constructor used by dynamic creation
class CEditControlView : public CFormView
{
public:
CEditControlView(); // protected constructor used by dynamic creation
为CEditControlView上的编辑控件添加控件型变量m_editCtrl
为对话框添加OnSize消息,使编辑框与对话框等大
- void CEditControlView::OnSize(UINT nType, int cx, int cy)
- {
- CFormView::OnSize(nType, cx, cy);
- // TODO: Add your message handler code here
- CFormView::ShowScrollBar(SB_VERT,FALSE);
- CFormView::ShowScrollBar(SB_HORZ,FALSE);
- //编辑框与窗口大小一样
- if (GetSafeHwnd())
- {
- if (m_editCtrl.GetSafeHwnd())
- {
- CRect rect(0,0,cx,cy);
- m_editCtrl.MoveWindow(&rect);
- }
- }
- }
void CEditControlView::OnSize(UINT nType, int cx, int cy)
{
CFormView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
CFormView::ShowScrollBar(SB_VERT,FALSE);
CFormView::ShowScrollBar(SB_HORZ,FALSE);
//编辑框与窗口大小一样
if (GetSafeHwnd())
{
if (m_editCtrl.GetSafeHwnd())
{
CRect rect(0,0,cx,cy);
m_editCtrl.MoveWindow(&rect);
}
}
}
现在创建关联树控件的视图类
CLeftPaneView : public CFormView关联对话框 IDD_TREEVIEW。
为CLeftPaneView树控件关联一个控件类型的变量m_treeCtrl
为对话框添加OnSize消息,使树控件与对话框等大
- void CLeftPaneView::OnSize(UINT nType, int cx, int cy)
- {
- CFormView::OnSize(nType, cx, cy);
- // TODO: Add your message handler code here
- if (GetSafeHwnd())
- {
- CRect rect;
- GetClientRect(&rect);
- if (m_treeCtrl.GetSafeHwnd())
- m_treeCtrl.MoveWindow(&rect);
- }
- }
void CLeftPaneView::OnSize(UINT nType, int cx, int cy)
{
CFormView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
if (GetSafeHwnd())
{
CRect rect;
GetClientRect(&rect);
if (m_treeCtrl.GetSafeHwnd())
m_treeCtrl.MoveWindow(&rect);
}
}
添加OnInitialUpdate()虚函数,初始化树控件
- void CLeftPaneView::OnInitialUpdate()
- {
- CFormView::OnInitialUpdate();
- // TODO: Add your specialized code here and/or call the base class
- m_ImageList.Create(IDB_BITMAP, 16, 1, RGB(255, 0, 255));
- m_treeCtrl.SetImageList(&m_ImageList, LVSIL_NORMAL);
- m_hSplitterView = m_treeCtrl.InsertItem("Splitter View", 0, 0);
- m_hListCtrlView = m_treeCtrl.InsertItem("ListCtrl View", 1, 1);
- m_hEditView = m_treeCtrl.InsertItem("EditCtrl View", 2, 2);
- }
void CLeftPaneView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
m_ImageList.Create(IDB_BITMAP, 16, 1, RGB(255, 0, 255));
m_treeCtrl.SetImageList(&m_ImageList, LVSIL_NORMAL);
m_hSplitterView = m_treeCtrl.InsertItem("Splitter View", 0, 0);
m_hListCtrlView = m_treeCtrl.InsertItem("ListCtrl View", 1, 1);
m_hEditView = m_treeCtrl.InsertItem("EditCtrl View", 2, 2);
}
4、创建一个切分窗口类
其实质是在切分窗口添加编辑视图和列表视图对象。
源文件中添加
- #include "ListControlView.h"
- #include "EditControlView.h"
#include "ListControlView.h"
#include "EditControlView.h"
为了后面可以new CSplitterView将构造函数改为publlic属性(默认为protected)
- class CSplitterView : public CView
- {
- public: // changed from protected
- CSplitterView(); // protected constructor used by dynamic creation
- //
- //
- };
class CSplitterView : public CView
{
public: // changed from protected
CSplitterView(); // protected constructor used by dynamic creation
//
//
};
- int CSplitterView::OnCreate(LPCREATESTRUCT lpCreateStruct)
- {
- if (CView::OnCreate(lpCreateStruct) == -1)
- return -1;
- // TODO: Add your specialized creation code here
- m_wndSplitter.CreateStatic(this, 2, 1);
- CCreateContext *pContext = (CCreateContext*) lpCreateStruct->lpCreateParams;
- m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CListControlView), CSize(150,0), pContext);
- m_wndSplitter.CreateView(1,0,RUNTIME_CLASS(CEditControlView), CSize(0,0), pContext);
- return 0;
- }
int CSplitterView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
m_wndSplitter.CreateStatic(this, 2, 1);
CCreateContext *pContext = (CCreateContext*) lpCreateStruct->lpCreateParams;
m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CListControlView), CSize(150,0), pContext);
m_wndSplitter.CreateView(1,0,RUNTIME_CLASS(CEditControlView), CSize(0,0), pContext);
return 0;
}
添加成员变量
- // Attributes
- public:
- CSplitterWnd m_wndSplitter;
// Attributes
public:
CSplitterWnd m_wndSplitter;
添加WM_CREATE、WM_SIZE消息响应
- int CSplitterView::OnCreate(LPCREATESTRUCT lpCreateStruct)
- {
- if (CView::OnCreate(lpCreateStruct) == -1)
- return -1;
- // TODO: Add your specialized creation code here
- m_wndSplitter.CreateStatic(this, 2, 1);
- CCreateContext *pContext = (CCreateContext*) lpCreateStruct->lpCreateParams;
- m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CListCtrlView), CSize(150,0), pContext);
- m_wndSplitter.CreateView(1,0,RUNTIME_CLASS(CEditCtrlView), CSize(0,0), pContext);
- return 0;
- }
- void CSplitterView::OnSize(UINT nType, int cx, int cy)
- {
- CView::OnSize(nType, cx, cy);
- // TODO: Add your message handler code here
- m_wndSplitter.MoveWindow(-2,-2,cx+4,cy+4);
- m_wndSplitter.SetRowInfo(0, cy-(cy/4), 0);
- m_wndSplitter.SetRowInfo(1, cy/4, 20);
- m_wndSplitter.RecalcLayout();
- }
int CSplitterView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
m_wndSplitter.CreateStatic(this, 2, 1);
CCreateContext *pContext = (CCreateContext*) lpCreateStruct->lpCreateParams;
m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CListCtrlView), CSize(150,0), pContext);
m_wndSplitter.CreateView(1,0,RUNTIME_CLASS(CEditCtrlView), CSize(0,0), pContext);
return 0;
}
void CSplitterView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
m_wndSplitter.MoveWindow(-2,-2,cx+4,cy+4);
m_wndSplitter.SetRowInfo(0, cy-(cy/4), 0);
m_wndSplitter.SetRowInfo(1, cy/4, 20);
m_wndSplitter.RecalcLayout();
}
5、创建右侧切分窗口的框架类
因为所有视图都要放在框架窗口中,所以,右面板需要一个框架窗口。
新建框架窗口类CRightPaneFrame,继承自CFrameWnd。
为了在框架中调用不同视图类,添加成员变量,并定义视图ID
- #include "SplitterView.h"
- #include "ListControlView.h"
- #include "EditControlView.h"
- #define VIEW_SPLITTER 1
- #define VIEW_LISTCTRL 2
- #define VIEW_EDIT 3
#include "SplitterView.h"
#include "ListControlView.h"
#include "EditControlView.h"
#define VIEW_SPLITTER 1
#define VIEW_LISTCTRL 2
#define VIEW_EDIT 3
- public:
- CSplitterView* m_pSplitterView;
- CListControlView* m_pListCtrlView;
- CEditControlView* m_pEditCtrlView;
- UINT m_nCurrentViewID;
public:
CSplitterView* m_pSplitterView;
CListControlView* m_pListCtrlView;
CEditControlView* m_pEditCtrlView;
UINT m_nCurrentViewID;
添加虚函数
- BOOL CRightPaneFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
- {
- // TODO: Add your specialized code here and/or call the base class
- // TODO: Add your specialized code here and/or call the base class
- m_pSplitterView = new CSplitterView;
- m_pSplitterView->Create(NULL, NULL, 0L, CFrameWnd::rectDefault, this, VIEW_SPLITTER, pContext);
- SetActiveView(m_pSplitterView);
- m_pSplitterView->ShowWindow(SW_SHOW);
- m_pSplitterView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
- m_nCurrentViewID = VIEW_SPLITTER;
- m_pListCtrlView = new CListControlView;
- ((CView*) m_pListCtrlView)->Create(NULL, NULL, 0L, CFrameWnd::rectDefault, this, VIEW_LISTCTRL, pContext);
- m_pListCtrlView->ShowWindow(SW_HIDE);
- m_pListCtrlView->SetDlgCtrlID(VIEW_LISTCTRL);
- m_pEditCtrlView = new CEditControlView;
- ((CView*) m_pEditCtrlView)->Create(NULL, NULL, 0L, CFrameWnd::rectDefault, this, VIEW_EDIT, pContext);
- m_pEditCtrlView->ShowWindow(SW_HIDE);
- m_pEditCtrlView->SetDlgCtrlID(VIEW_EDIT);
- RecalcLayout();
- return TRUE;
- // return CFrameWnd::OnCreateClient(lpcs, pContext);
- }
BOOL CRightPaneFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class
// TODO: Add your specialized code here and/or call the base class
m_pSplitterView = new CSplitterView;
m_pSplitterView->Create(NULL, NULL, 0L, CFrameWnd::rectDefault, this, VIEW_SPLITTER, pContext);
SetActiveView(m_pSplitterView);
m_pSplitterView->ShowWindow(SW_SHOW);
m_pSplitterView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
m_nCurrentViewID = VIEW_SPLITTER;
m_pListCtrlView = new CListControlView;
((CView*) m_pListCtrlView)->Create(NULL, NULL, 0L, CFrameWnd::rectDefault, this, VIEW_LISTCTRL, pContext);
m_pListCtrlView->ShowWindow(SW_HIDE);
m_pListCtrlView->SetDlgCtrlID(VIEW_LISTCTRL);
m_pEditCtrlView = new CEditControlView;
((CView*) m_pEditCtrlView)->Create(NULL, NULL, 0L, CFrameWnd::rectDefault, this, VIEW_EDIT, pContext);
m_pEditCtrlView->ShowWindow(SW_HIDE);
m_pEditCtrlView->SetDlgCtrlID(VIEW_EDIT);
RecalcLayout();
return TRUE;
// return CFrameWnd::OnCreateClient(lpcs, pContext);
}
添加切换视图的函数
public:
void SwitchToView(UINT nView);
- void CRightPaneFrame::SwitchToView(UINT nView)
- {
- CView* pOldActiveView = GetActiveView();
- CView* pNewActiveView = NULL;
- switch (nView)
- {
- case VIEW_SPLITTER:
- pNewActiveView = (CView*) m_pSplitterView;
- break;
- case VIEW_LISTCTRL:
- pNewActiveView = (CView*) m_pListCtrlView;
- break;
- case VIEW_EDIT:
- pNewActiveView = (CView*) m_pEditCtrlView;
- break;
- }
- if (pNewActiveView)
- {
- // don't switch when views are the same
- if (pOldActiveView == pNewActiveView) return;//不变
- SetActiveView(pNewActiveView);//改变活动的视图
- pNewActiveView->ShowWindow(SW_SHOW);//显示新的视图
- pNewActiveView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
- pOldActiveView->ShowWindow(SW_HIDE);//隐藏旧的视图
- pOldActiveView->SetDlgCtrlID(m_nCurrentViewID);
- m_nCurrentViewID = nView;
- RecalcLayout();//调整框架窗口
- }
- }
void CRightPaneFrame::SwitchToView(UINT nView)
{
CView* pOldActiveView = GetActiveView();
CView* pNewActiveView = NULL;
switch (nView)
{
case VIEW_SPLITTER:
pNewActiveView = (CView*) m_pSplitterView;
break;
case VIEW_LISTCTRL:
pNewActiveView = (CView*) m_pListCtrlView;
break;
case VIEW_EDIT:
pNewActiveView = (CView*) m_pEditCtrlView;
break;
}
if (pNewActiveView)
{
// don't switch when views are the same
if (pOldActiveView == pNewActiveView) return;//不变
SetActiveView(pNewActiveView);//改变活动的视图
pNewActiveView->ShowWindow(SW_SHOW);//显示新的视图
pNewActiveView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
pOldActiveView->ShowWindow(SW_HIDE);//隐藏旧的视图
pOldActiveView->SetDlgCtrlID(m_nCurrentViewID);
m_nCurrentViewID = nView;
RecalcLayout();//调整框架窗口
}
}
注意:
pNewActiveView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
实际上AFX_IDW_PANE_FIRST是为了解决多个VIEW的情况下消息转发的问题,这是MFC内部使用的一个固定的值,所有当前的活动视图都会切换到AFX_IDW_PANE_FIRST这个ID,主窗口收到的一些消息(比如命令、通知等等消息)会转发给活动视图来处理,框架通过这个ID来定位活动视图。
当在某个SDI应用程序中使用多个视图并支持视图切换时,很容易忽略这点,造成某些消息得不到正确的响应,
因此当激活某个视图时也要把这个视图的ID改成AFX_IDW_PANE_FIRST。
当主框架调整窗口布局时,即调用RecalcLayout()这个函数时,会将ID为AFX_IDW_PANE_FIRST的窗口/视(必须可见)作为最后一个视图进行拉伸以填充剩余的区域。
6.左面版添加视图类成员变量
在左面版也即树视中添加成员变量,包含右面板和树项
- // Attributes
- public:
- CImageList m_ImageList;
- HTREEITEM m_hSplitterView;
- HTREEITEM m_hListCtrlView;
- HTREEITEM m_hEditView;
- CRightPaneFrame* m_pRightPaneFrame;
// Attributes
public:
CImageList m_ImageList;
HTREEITEM m_hSplitterView;
HTREEITEM m_hListCtrlView;
HTREEITEM m_hEditView;
CRightPaneFrame* m_pRightPaneFrame;
头文件class CLeftPaneView : public CFormView前加前置声明,以便使用VIEW_SPLITTER等宏定义
- class CRightPaneFrame;
class CRightPaneFrame;
在源文件加
- #include "RightPaneFrame.h"
#include "RightPaneFrame.h"
添加当树形控件选项改变时消息响应,右边视图变化
- void CLeftPaneView::OnSelchangedTree(NMHDR* pNMHDR, LRESULT* pResult)
- {
- NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
- // TODO: Add your control notification handler code here
- UINT nView = 0;
- HTREEITEM hSelectedItem = m_treeCtrl.GetSelectedItem();
- if (hSelectedItem == m_hSplitterView)
- nView = VIEW_SPLITTER;
- else
- if (hSelectedItem == m_hListCtrlView)
- nView = VIEW_LISTCTRL;
- else
- if (hSelectedItem == m_hEditView)
- nView = VIEW_EDIT;
- if (nView) m_pRightPaneFrame->SwitchToView(nView);
- *pResult = 0;
- }
void CLeftPaneView::OnSelchangedTree(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
// TODO: Add your control notification handler code here
UINT nView = 0;
HTREEITEM hSelectedItem = m_treeCtrl.GetSelectedItem();
if (hSelectedItem == m_hSplitterView)
nView = VIEW_SPLITTER;
else
if (hSelectedItem == m_hListCtrlView)
nView = VIEW_LISTCTRL;
else
if (hSelectedItem == m_hEditView)
nView = VIEW_EDIT;
if (nView) m_pRightPaneFrame->SwitchToView(nView);
*pResult = 0;
}
7、修改MainFrame,创建静态切分窗口
在源文件中添加
- #include "LeftPaneView.h"
- #include "RightPaneFrame.h"
#include "LeftPaneView.h"
#include "RightPaneFrame.h"
修改OnCreateClient函数
- BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
- {
- // TODO: Add your specialized code here and/or call the base class
- if (!m_wndSplitter.CreateStatic(this, 1, 2))
- {
- TRACE0("Failed to create splitter window\n");
- return FALSE;
- }
- // Get the client rect first for calc left pane size
- CRect rect;
- GetClientRect(&rect);
- // create the left tree view first.
- if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CLeftPaneView), CSize(rect.Width()/3, 0), pContext))
- {
- TRACE0("Failed to create left pane view\n");
- return FALSE;
- }
- // The right pane is a frame which and contain several different views.
- // The is can be set to active or non-active
- if (!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CRightPaneFrame), CSize(0, 0), pContext))
- {
- TRACE0("Failed to create right pane frame\n");
- return FALSE;
- }
- CLeftPaneView* pLeftPaneView = (CLeftPaneView*) m_wndSplitter.GetPane(0,0);
- pLeftPaneView->m_pRightPaneFrame = (CRightPaneFrame*) m_wndSplitter.GetPane(0,1);
- // Set the left pane as the active view
- SetActiveView((CView*) m_wndSplitter.GetPane(0, 0));
- return TRUE;
- }