鉴于CSplitterWnd资料很少(MSDN上也说的很简单,Sample我也就不想吐槽了),同时网上博客又几乎是千篇一律的转载。现将个人的一点经验拿出来和大家分享,希望对他人有所帮助。不足之处还望批评指正。
最终效果如下:
分割窗体就是把一个窗体分割成多个面板,面板就是放各种控件或视图的容器。分割窗体有两种形式,静态和动态。两种形式的区别在于动态的可以收拢和展开,静态的则不能。动态分割只能创建2*2的分割窗口,而静态分割可以创建16*16的分割窗口。
好了,进入正题。在VS或VC++6.0中建立一个多文档或者单文档,按照向导一直下一步即可。本文创建的是多文档,单文档相对简单一些。
创建好之后,在ChildFrm.h中添加两个窗口分割变量:
// Attributes
protected:
CSplitterWnd m_wndSplitter1;
CSplitterWnd m_wndSplitter;
然后选择工程的类视图,右键ChildFrm属性,添加Overrides中的OnCreateClient方法。如果是单文档的话在MainFrm中添加!
修改OnCreateClient方法如下:
BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
{
// Create 2*2 nested dynamic splitter
// TODO: Add your specialized code here and/or call the base class
return m_wndSplitter.Create(this,
2, 2, // TODO: adjust the number of rows, columns
CSize(10, 10), // TODO: adjust the minimum pane size
pContext);
//return CMDIChildWnd::OnCreateClient(lpcs, pContext);
Create a static splitter with 1 rows, 3 columns
//m_wndSplitter.CreateStatic(this, 1, 3); // create a splitter with 1 rows, 3 columns
//m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CViewLeft), CSize(0, 0), pContext); // create view with 0 rows, 0 columns
//m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CViewMiddle), CSize(0, 0), pContext); // create view with 0 rows, 1 columns
//m_wndSplitter.CreateView(0, 2, RUNTIME_CLASS(CViewRight), CSize(0, 0), pContext); // create view with 0 rows, 2 columns
//m_wndSplitter.SetColumnInfo(0, 400, 10); // set the width of column, 0 column, ideal width is 200dip,min width is 10dip
//m_wndSplitter.SetColumnInfo(1, 400, 10); // set the width of column, 0 column, ideal width is 200dip,min width is 10dip
//m_wndSplitter.SetColumnInfo(2, 400, 10); // set the width of column, 0 column, ideal width is 200dip,min width is 10dip
m_wndSplitter.SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
//Create a static splitter with 2 rows,1 columns
if (!m_wndSplitter.CreateStatic(this, 2, 1, WS_CHILD|WS_VISIBLE))
{
TRACE("Failed to Create StaticSplitter\n");
return NULL;
}
//set view
pContext->m_pNewViewClass = RUNTIME_CLASS(CViewRight);
CRect rect;
this->GetClientRect(&rect);
SIZE size;
size.cx = rect.Width();
size.cy = rect.Height()/3;
m_wndSplitter.CreateView(0, 0, pContext->m_pNewViewClass, size, pContext);
//m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CViewLeft), CSize(0, 0), pContext); // create view with 0 rows, 0 columns
//m_wndSplitter.SetRowInfo(0, 200, 10); // set the width of column, 0 column, ideal width is 250dip,min width is 10dip
pContext->m_pNewViewClass = RUNTIME_CLASS(CViewMiddle);
if (!m_wndSplitter1.Create(
&m_wndSplitter, // our parent window is the first splitter
2, 2, // TODO: adjust the number of rows, columns
CSize(10, 10), // TODO: adjust the minimum pane size
pContext,
WS_CHILD|WS_VISIBLE|SPLS_DYNAMIC_SPLIT|WS_HSCROLL|WS_VSCROLL,
m_wndSplitter.IdFromRowCol(1, 0)))
{
TRACE("Failed to create the nested dynamic splitter\n");
}
return TRUE;
}
RUNTIME_CLASS是MFC中的一个宏,用来动态创建一个类。
这里是我做了三种分割方式的测试,第一种是直接创建了一个2*2的动态分割窗口,没有修改视图;第二种是创建的一个一行三列的静态分割窗口,并且分别为之创建了三个视图,然后设置的了每一列的宽度;最后一种是静态分割和动态分割嵌套使用,先使用静态分割,将整个窗口分割成为两行一列,分割完成后为第一行创建视图,设置视图高度为整个窗口的1/3,然后更改视图,使得随后动态分割的窗口绑定不同的视图,再对第二行使用动态分割,将第二行分割成2*2的动态分割窗口。
CViewLeft、CViewRight、CViewMiddle这三个类均继承自CView,只需重写下每个类的OnDraw方法即可
void CViewLeft::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
// TODO: add draw code here
CPaintDC* dc = (CPaintDC*)pDC;
CRect rect,fillrect;
CBrush brush;
brush.CreateSolidBrush(RGB(255, 0, 0));
this->GetClientRect(&rect);
dc->FillRect(&rect,&brush);
brush.DeleteObject();
}
void CViewMiddle::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
// TODO: add draw code here
CPaintDC* dc = (CPaintDC*)pDC;
CRect rect,fillrect;
CBrush brush;
brush.CreateSolidBrush(RGB(0, 255, 0));
this->GetClientRect(&rect);
dc->FillRect(&rect,&brush);
brush.DeleteObject();
}
void CViewRight::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
// TODO: add draw code here
CPaintDC* dc = (CPaintDC*)pDC;
CRect rect,fillrect;
CBrush brush;
brush.CreateSolidBrush(RGB(0, 0, 255));
this->GetClientRect(&rect);
dc->FillRect(&rect,&brush);
brush.DeleteObject();
}
一个CSplitterWnd对象通常被嵌入CFrameWnd或CMDIChildWnd父对象。一般使用Create或者CreateStatic分割窗口完毕,可使用SetColumnInfo和SetRowInfo来调整这些最小值,为使用其设置过的行或列则会自动分配大小。
定制属于自己的SplitterWnd:拖动滚动条时只显示一行或者一列
/*****************************************************************
Filename: Splitter.h
Contents: Implemetation of CSplitter class
Authors:
Created date:
Last Modified date:
Revision History:
Used by:
Uses:
Build Notes:
See Also:
Copyright: (c) 2015 by All rights reserved.
*********************