第二章 第七小节Duilib中的CContainerUI容器控件-所有容器类的父控件

  这一小节正式进入容器控件类的讲解,除了少部分简单控件,许多控件是由多个子控件组合而成的复杂控件。这种复杂控件由多个控件组成,控件间如何相互排版是控件组合中最关键的问题。控件的布局分为绝对布局和相对布局。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 < UIEVENT__MOUSEEND ) {
            if( m_pParent != NULL ) m_pParent->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 < m_items.GetSize(); it++ ) {
                    CControlUI* pControl = static_cast<CControlUI*>(m_items[it]);
                    if( pControl == pStopControl ) return false;
                    if( !pControl->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 < m_items.GetSize(); it++ ) {
                    CControlUI* pControl = static_cast<CControlUI*>(m_items[it]);
                    if( pControl == pStopControl ) return false;
                    if( !pControl->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.作者答疑


  如有疑问,请留言。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值