1.简介
CControlUI中有三个重要的参数,分别为:
- RECT m_rcItem; //控件实际大小及位置
- SIZE m_cxyFixed; //控件预设大小
- SIZE m_cXY; //控件预设位置
2.非float控件的讨论
控件的浮动与非浮动由参数 m_bFloat 标识,此处讨论 m_bFloat = false 的情形。
2.1 m_rcItem
//获取控件大小及位置
const RECT& CControlUI::GetPos() const
{
return m_rcItem;
}
//设置控件大小及位置:1.由父控件设置
void CControlUI::SetPos(RECT rc)
{
//设置控件大小位置
m_rcItem = rc;
//控件大小位置改变消息处理
if( !m_bSetPos )
{
m_bSetPos = true;
if( OnSize ) OnSize(this);
m_bSetPos = false;
}
//计算需要重新刷新的区域,并进行刷新
m_pManager->Invalidate(invalidateRc);
}
2.2 m_cxyFixed
设置 m_cxyFixed.cy 与下面设置 m_cxyFixed.cx 方式相同,不再重复。
int CControlUI::GetFixedWidth() const
{
return m_cxyFixed.cx;
}
//预设置控件大小:1.父控件设置 2.通过“pos”参数时,pos.right-pos.left 3.通过“width”参数
void CControlUI::SetFixedWidth(int cx)
{
//设置大小
m_cxyFixed.cx = cx;
//更新父控件布局
NeedParentUpdate();
}
重点:当容器在设置子控件布局时,会使用该参数估计子控件大小,从而为子控件分配实际大小及位置: SetPos()。
SIZE CControlUI::EstimateSize(SIZE szAvailable)
{
return m_cxyFixed;
}
2.3 m_cXY
预设置控件的位置。
// 实际大小位置使用GetPos获取,这里得到的是预设的参考值(代码原注释)
SIZE CControlUI::GetFixedXY() const
{
return m_cXY;
}
//
void CControlUI::SetFixedXY(SIZE szXY)
{
m_cXY.cx = szXY.cx;
m_cXY.cy = szXY.cy;
NeedParentUpdate();
}
3.float控件的讨论
浮动控件与非浮动控件的主要区别在于,当控件的预设大小改变时,是否重新刷新父控件中子控件的布局。举例如下:
void CControlUI::SetFixedXY(SIZE szXY)
{
m_cXY.cx = szXY.cx;
m_cXY.cy = szXY.cy;
if( !m_bFloat )
NeedParentUpdate();
else
NeedUpdate();
}
另外一个区别在 SetPos() 函数中:
void CControlUI::SetPos(RECT rc)
{
//设置实际位置及大小
......
//更新预设控件大小及位置
if( m_bFloat )
{
CControlUI* pParent = GetParent();
if( pParent != NULL )
{
RECT rcParentPos = pParent->GetPos();
if( m_cXY.cx >= 0 )
m_cXY.cx = m_rcItem.left - rcParentPos.left;
else
m_cXY.cx = m_rcItem.right - rcParentPos.right;
if( m_cXY.cy >= 0 )
m_cXY.cy = m_rcItem.top - rcParentPos.top;
else
m_cXY.cy = m_rcItem.bottom - rcParentPos.bottom;
m_cxyFixed.cx = m_rcItem.right - m_rcItem.left;
m_cxyFixed.cy = m_rcItem.bottom - m_rcItem.top;
}
}
//刷新重绘无效区域
......
}
注:其实 SetPos() 不仅会调整自身的位置和大小,如果其包含其他控件,则它会调整子控件的位置和大小。
4.结束
m_rcItem 为控件的实际大小,实际所占用的位置。
m_cxyFixed 为如果控件在某个容器中时,希望父容器能够为其分配的大小,但是仅仅是希望。一般情况下父容器也是很通情达理的。
父容器会调用子控件的 EstimateSize() 函数来询问子控件所希望设置的大小即 m_cxyFixed。
SetPos() 函数同样重要,不仅设置自己的位置,也会调整子控件的位置(前提它是容器且有子控件)。
5.附
(1) NeedUpdate() 函数
在各种调整预设大小的函数中,我们看到各种调用 NeedUpdate() 函数,在此简介一下:
void CControlUI::NeedUpdate()
{
if( !IsVisible() )
return;
m_bUpdateNeeded = true;
Invalidate();
//通过设置m_pManager中的 m_bUpdateNeeded 设置控件大小更新
if( m_pManager != NULL )
m_pManager->NeedUpdate();
}
m_bUpdateNeeded 主要用在处理 CPaintManagerUI::MessageHandler() 中的 WM_PAINT 消息时,判断是否需要重设控件位置及大小:
case WM_PAINT:
{
//判断是否需要重绘
if( m_bUpdateNeeded )
{
m_bUpdateNeeded = false;
RECT rcClient = { 0 };
::GetClientRect(m_hWndPaint, &rcClient);
if( !::IsRectEmpty(&rcClient) )
{
if( m_pRoot->IsUpdateNeeded() ) //是否需要更新
{
m_pRoot->SetPos(rcClient);
}
else
{
//循环处理需要更新的控件
CControlUI* pControl = NULL;
while( pControl = m_pRoot->FindControl(__FindControlFromUpdate, NULL, UIFIND_VISIBLE | UIFIND_ME_FIRST) )
{
pControl->SetPos( pControl->GetPos() );
}
}
//第一次绘制的话,发送 DUI_MSGTYPE_WINDOWINIT 消息
}
}
//重绘......
// 如果仍需要调整大小,再调用 InvalidateRect() 更新刷新区域
// 在下一次处理 WM_PAINT 消息时进行重绘
if( m_bUpdateNeeded )
{
::InvalidateRect(m_hWndPaint, NULL, FALSE);
}
}
return true;
当然 NeedParentUpdate() 也一样,效果和 NeedUpdate() 基本相同,只是把父控件也设置成了需要更新。
void CControlUI::NeedParentUpdate()
{
if( GetParent() )
{
GetParent()->NeedUpdate();
GetParent()->Invalidate();
}
else
{
NeedUpdate();
}
if( m_pManager != NULL )
m_pManager->NeedUpdate();
}
(2) Invalidate() 函数
在 SetPos() 的最后一句,调用了 m_pManager->Invalidate(invalidateRc); Invalidate() 函数的效果是更新刷新区域,在下一次处理 WM_PAINT 消息时进行重绘。
下面看下控件的 Invalidate() 函数的实现:
void CControlUI::Invalidate()
{
if( !IsVisible() ) return; //不可见就没有必要了
RECT invalidateRc = m_rcItem;
CControlUI* pParent = this;
RECT rcTemp;
RECT rcParent;
//循环搜索控件的交集,即需要重绘的区域
while( pParent = pParent->GetParent() )
{
rcTemp = invalidateRc;
rcParent = pParent->GetPos();
if( !::IntersectRect(&invalidateRc, &rcTemp, &rcParent) )
{
return;
}
}
//调用 m_pManager 的 Invalidate() 函数实现系统重绘
if( m_pManager != NULL )
m_pManager->Invalidate(invalidateRc);
}
看看 m_pManager 的 Invalidate() 函数:
void CPaintManagerUI::Invalidate(RECT& rcItem)
{
::InvalidateRect(m_hWndPaint, &rcItem, FALSE);
}
::InvalidateRect() 系统函数会将 rcItem 区域添加无效区域中,在下次处理 WM_PAINT 消息时进行重绘。
1146

被折叠的 条评论
为什么被折叠?



