这一小节正式进入容器控件类的讲解,除了少部分简单控件,许多控件是由多个子控件组合而成的复杂控件。这种复杂控件由多个控件组成,控件间如何相互排版是控件组合中最关键的问题。控件的布局分为绝对布局和相对布局。m_bFloat为真时,绝对布局(按坐标位置),否则为相对布局。 绝对布局,设置pos属性,他包含四个字段,分别以为了控件的左上右下四个坐标的位置。 相对布局,可设置width和height属性。如果控件或者布局的大小是固定的,那么就需要设置width和height属性,如果想让控件或者布局根据窗体的大小而自动调整大小和位置,就不设置这两个属性。在相对布局中,微调控件位置的的属性有inset、padding,这几个属性只在相对布局中,才会有效。 inset,这是给容器控件使用的,使用后他所包含的所有使用相对布局的元素,都会被限制在设置的范围内,适合对容器内所用元素进行整体的坐标控制。padding,它是相对布局中最常用的属性!用来设置相对于前一个控件的位置,这个属性是控件位置微调的关键。一般只用他的前两个字段,设置左边距和上边距。如果我想整体让这四个控件向右位移10像素,那么我只要设置第一个按钮的padding属性为padding=“10,0,0,0”,就可以了,其他布局完全不需要修改! 以上啰嗦的介绍了下容器控件布局的关键设置,下面来阅读下源码,如下所示:
//容器控件通用接口
class IContainerUI
{
public:
virtual CControlUI* GetItemAt(int iIndex) const = 0;
virtual int GetItemIndex(CControlUI* pControl) const = 0;
virtual bool SetItemIndex(CControlUI* pControl, int iIndex) = 0;
virtual int GetCount() const = 0;
virtual bool Add(CControlUI* pControl) = 0;
virtual bool AddAt(CControlUI* pControl, int iIndex) = 0;
virtual bool Remove(CControlUI* pControl) = 0;
virtual bool RemoveAt(int iIndex) = 0;
virtual void RemoveAll() = 0;
};
/
//
class CScrollBarUI;
//容器控件定义
class UILIB_API CContainerUI : public CControlUI, public IContainerUI
{
DECLARE_DUICONTROL(CContainerUI)
public:
CContainerUI();
virtual ~CContainerUI();
public:
LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
//实现接口
CControlUI* GetItemAt(int iIndex) const;
int GetItemIndex(CControlUI* pControl) const;
bool SetItemIndex(CControlUI* pControl, int iIndex);
int GetCount() const;
bool Add(CControlUI* pControl);
bool AddAt(CControlUI* pControl, int iIndex);
bool Remove(CControlUI* pControl);
bool RemoveAt(int iIndex);
void RemoveAll();
void DoEvent(TEventUI& event);
void SetVisible(bool bVisible = true);
void SetInternVisible(bool bVisible = true);
void SetEnabled(bool bEnabled);
void SetMouseEnabled(bool bEnable = true);
virtual RECT GetInset() const;
virtual void SetInset(RECT rcInset); // 设置内边距,相当于设置客户区
virtual int GetChildPadding() const;
virtual void SetChildPadding(int iPadding);
virtual UINT GetChildAlign() const;
virtual void SetChildAlign(UINT iAlign);
virtual UINT GetChildVAlign() const;
virtual void SetChildVAlign(UINT iVAlign);
virtual bool IsAutoDestroy() const;
virtual void SetAutoDestroy(bool bAuto);
virtual bool IsDelayedDestroy() const;
virtual void SetDelayedDestroy(bool bDelayed);
virtual bool IsMouseChildEnabled() const;
virtual void SetMouseChildEnabled(bool bEnable = true);
virtual int FindSelectable(int iIndex, bool bForward = true) const;
RECT GetClientPos() const;
void SetPos(RECT rc, bool bNeedInvalidate = true);
void Move(SIZE szOffset, bool bNeedInvalidate = true);
bool DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl);
void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue);
void SetManager(CPaintManagerUI* pManager, CControlUI* pParent, bool bInit = true);
CControlUI* FindControl(FINDCONTROLPROC Proc, LPVOID pData, UINT uFlags);
bool SetSubControlText(LPCTSTR pstrSubControlName,LPCTSTR pstrText);
bool SetSubControlFixedHeight(LPCTSTR pstrSubControlName,int cy);
bool SetSubControlFixedWdith(LPCTSTR pstrSubControlName,int cx);
bool SetSubControlUserData(LPCTSTR pstrSubControlName,LPCTSTR pstrText);
CDuiString GetSubControlText(LPCTSTR pstrSubControlName);
int GetSubControlFixedHeight(LPCTSTR pstrSubControlName);
int GetSubControlFixedWdith(LPCTSTR pstrSubControlName);
const CDuiString GetSubControlUserData(LPCTSTR pstrSubControlName);
CControlUI* FindSubControl(LPCTSTR pstrSubControlName);
//横竖滚动条
virtual SIZE GetScrollPos() const;
virtual SIZE GetScrollRange() const;
virtual void SetScrollPos(SIZE szPos, bool bMsg = true);
virtual void SetScrollStepSize(int nSize);
virtual int GetScrollStepSize() const;
virtual void LineUp();
virtual void LineDown();
virtual void PageUp();
virtual void PageDown();
virtual void HomeUp();
virtual void EndDown();
virtual void LineLeft();
virtual void LineRight();
virtual void PageLeft();
virtual void PageRight();
virtual void HomeLeft();
virtual void EndRight();
virtual void EnableScrollBar(bool bEnableVertical = true, bool bEnableHorizontal = false);
virtual CScrollBarUI* GetVerticalScrollBar() const;
virtual CScrollBarUI* GetHorizontalScrollBar() const;
protected:
virtual void SetFloatPos(int iIndex);
virtual void ProcessScrollBar(RECT rc, int cxRequired, int cyRequired);
protected:
CStdPtrArray m_items;//子控件列表
RECT m_rcInset;
int m_iChildPadding;
UINT m_iChildAlign;
UINT m_iChildVAlign;
bool m_bAutoDestroy;
bool m_bDelayedDestroy;
bool m_bMouseChildEnabled;
int m_nScrollStepSize;
CScrollBarUI* m_pVerticalScrollBar;
CScrollBarUI* m_pHorizontalScrollBar;
CDuiString m_sVerticalScrollBarStyle;
CDuiString m_sHorizontalScrollBarStyle;
};
以上代码包含容器控件的基本属性和方法,接下来重点解析几个关键函数DoEvent和DoPaint,DoEvent函数代码如下:
void CContainerUI::DoEvent(TEventUI& event)
{
if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type DoEvent(event);
else CControlUI::DoEvent(event);
return;
}
if( event.Type == UIEVENT_SETFOCUS )
{
m_bFocused = true;
return;
}
if( event.Type == UIEVENT_KILLFOCUS )
{
m_bFocused = false;
return;
}
if( m_pVerticalScrollBar != NULL && m_pVerticalScrollBar->IsVisible() && m_pVerticalScrollBar->IsEnabled() )
{
if( event.Type == UIEVENT_KEYDOWN )
{
switch( event.chKey ) {
case VK_DOWN:
LineDown();
return;
case VK_UP:
LineUp();
return;
case VK_NEXT:
PageDown();
return;
case VK_PRIOR:
PageUp();
return;
case VK_HOME:
HomeUp();
return;
case VK_END:
EndDown();
return;
}
}
else if( event.Type == UIEVENT_SCROLLWHEEL )
{
switch( LOWORD(event.wParam) ) {
case SB_LINEUP:
LineUp();
return;
case SB_LINEDOWN:
LineDown();
return;
}
}
}
if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() && m_pHorizontalScrollBar->IsEnabled() ) {
if( event.Type == UIEVENT_KEYDOWN )
{
switch( event.chKey ) {
case VK_DOWN:
LineRight();
return;
case VK_UP:
LineLeft();
return;
case VK_NEXT:
PageRight();
return;
case VK_PRIOR:
PageLeft();
return;
case VK_HOME:
HomeLeft();
return;
case VK_END:
EndRight();
return;
}
}
else if( event.Type == UIEVENT_SCROLLWHEEL )
{
switch( LOWORD(event.wParam) ) {
case SB_LINEUP:
LineLeft();
return;
case SB_LINEDOWN:
LineRight();
return;
}
}
}
CControlUI::DoEvent(event);
}
还有就是DoPaint函数,代码如下:
bool CContainerUI::DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl)
{
RECT rcTemp = { 0 };
if( !::IntersectRect(&rcTemp, &rcPaint, &m_rcItem) ) return true;
CRenderClip clip;
CRenderClip::GenerateClip(hDC, rcTemp, clip);
CControlUI::DoPaint(hDC, rcPaint, pStopControl);
if( m_items.GetSize() > 0 ) {
RECT rcInset = GetInset();
RECT rc = m_rcItem;
rc.left += rcInset.left;
rc.top += rcInset.top;
rc.right -= rcInset.right;
rc.bottom -= rcInset.bottom;
if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) rc.right -= m_pVerticalScrollBar->GetFixedWidth();
if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
if( !::IntersectRect(&rcTemp, &rcPaint, &rc) ) {
for( int it = 0; it IsVisible() ) continue;
if( !::IntersectRect(&rcTemp, &rcPaint, &pControl->GetPos()) ) continue;
if( pControl ->IsFloat() ) {
if( !::IntersectRect(&rcTemp, &m_rcItem, &pControl->GetPos()) ) continue;
if( !pControl->Paint(hDC, rcPaint, pStopControl) ) return false;
}
}
}
else {
CRenderClip childClip;
CRenderClip::GenerateClip(hDC, rcTemp, childClip);
for( int it = 0; it IsVisible() ) continue;
if( !::IntersectRect(&rcTemp, &rcPaint, &pControl->GetPos()) ) continue;
if( pControl->IsFloat() ) {
if( !::IntersectRect(&rcTemp, &m_rcItem, &pControl->GetPos()) ) continue;
CRenderClip::UseOldClipBegin(hDC, childClip);
if( !pControl->Paint(hDC, rcPaint, pStopControl) ) return false;
CRenderClip::UseOldClipEnd(hDC, childClip);
}
else {
if( !::IntersectRect(&rcTemp, &rc, &pControl->GetPos()) ) continue;
if( !pControl->Paint(hDC, rcPaint, pStopControl) ) return false;
}
}
}
}
//垂直滚动条
if( m_pVerticalScrollBar != NULL && m_pVerticalScrollBar->IsVisible() ) {
if( m_pVerticalScrollBar == pStopControl ) return false;
if( ::IntersectRect(&rcTemp, &rcPaint, &m_pVerticalScrollBar->GetPos()) ) {
if( !m_pVerticalScrollBar->Paint(hDC, rcPaint, pStopControl) ) return false;
}
}
//水平滚动条
if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() ) {
if( m_pHorizontalScrollBar == pStopControl ) return false;
if( ::IntersectRect(&rcTemp, &rcPaint, &m_pHorizontalScrollBar->GetPos()) ) {
if( !m_pHorizontalScrollBar->Paint(hDC, rcPaint, pStopControl) ) return false;
}
}
return true;
}
以上绘制函数也是个迭代绘制,先自身绘制,然后往子控件绘制,直到所有的绘制完毕!
2.作者答疑如有疑问,请留言。