vc层叠式窗体控件指南[组图](4)
下一个任务是写一个允许我们添加面板到控件上的public方法。这没有什么困难。我们使窗体对象的指针作为参数传递,并设置新的面板如其所显示的一样。
int CStackedWndCtrl::AddPane( CWnd* pwndRubric, CWnd* pwndContent )
{
// 隐藏无论哪一个正在显示面板的内容窗体
//我们将总是显示最近添加的面板的内容窗体
for( int i = 0; i < m_arrPanes.GetSize(); i++ )
if( m_arrPanes[ i ]->m_bOpen )
m_arrPanes[ i ]->m_bOpen = FALSE;
//创建一个新的面板结构
PTDS_PANE pPane = new TDS_PANE;
if( pPane == NULL )
{
AfxMessageBox( "Failed to add a new pane to"
" the stack.
Out of memory." );
return -1;
}
// 拷贝指针到标题和内容窗体
//同时,设置这个面板为打开状态
pPane->m_pwndRubric = pwndRubric;
pPane->m_pwndContent = pwndContent;
pPane->m_bOpen = TRUE;
// 添加该新面板到栈的尾部
int iIndex = m_arrPanes.Add( pPane );
// 重新排列栈
RearrangeStack();
// 返回新面板的索引号
return iIndex;
}
在我们担心排列和显示面板之前(如果你想要测试这个代码,只要参考RearrangeStack
方法的调用 ),我们要确保在退出时该结构体被完全删除是非常重要的,以免内存泄漏。我们在析构器中执行该任务,如下所示:
CStackedWndCtrl::~CStackedWndCtrl()
{
for( int i = 0; i < m_arrPanes.GetSize(); i++ )
{
//删除标题窗体
m_arrPanes[ i ]->m_pwndRubric->DestroyWindow();
delete m_arrPanes[ i ]->m_pwndRubric;
// 删除内容窗体
m_arrPanes[ i ]->m_pwndContent->DestroyWindow();
delete m_arrPanes[ i ]->m_pwndContent;
// 删除结构体
delete m_arrPanes[ i ];
}
m_arrPanes.RemoveAll();
}
简单填充。我们遍历该面板上的数组,销毁每个窗体,然后删除每个窗体对象,然后删除每个面板对象,并且最后,从数组中移除所有指针。
这个功能足以使得CStackedWndCtrl类可以做它的工作。我们可以添加面板,同时它们(译注:指面板)在控件被销毁时被适当释放。
可视的魔力
None of it, 我想.排列和显示控件的算法是相当简单的。
我们遍历面板,通过一个预先估量消除顶部框架,m_iRubricHeight,它在演示程序中被设置为一个默认的值(可以自由测试)当我们点击打开的面板,我们用余下来要显示的标题窗体的数量来计算该面板的内容窗体的尺寸。请看下面的代码。
void CStackedWndCtrl::RearrangeStack()
{
CRect rFrame;
GetClientRect( &rFrame );
for( int i = 0; i < m_arrPanes.GetSize(); i++ )
{
// 标题窗体总是显示
m_arrPanes[ i ]->m_pwndRubric->SetWindowPos(
NULL,
0,
rFrame.top,
rFrame.Width(),
m_iRubricHeight,
SWP_NOZORDER | SWP_SHOWWINDOW );
// 只有已标记面板的内容窗体被显示
// 如果它们没有准备好,所有其他的都隐藏
if( m_arrPanes[ i ]->m_bOpen )
{
// 从框架的底部,去掉余下要显示的那些标题窗体的一样高度的尺寸
int iContentWndBottom = rFrame.bottom -
( ( m_arrPanes.GetSize() - i ) * m_iRubricHeight );
m_arrPanes[ i ]->m_pwndContent->SetWindowPos(
NULL,
0,
rFrame.top + m_iRubricHeight,
rFrame.Width(),
iContentWndBottom - rFrame.top,
SWP_NOZORDER | SWP_SHOWWINDOW );
//下一个标题窗体将被放置于该面板内容窗体的正下方
rFrame.top = iContentWndBottom;
}
else
m_arrPanes[ i ]->m_pwndContent->ShowWindow( SW_HIDE );
//框架的顶部偏移一个标题窗体的高度
rFrame.top += m_iRubricHeight;
}
}