duilib界面库给container添加滚动条后子控件不能正常显示的问题

container子控件需要任意在容器中任意拖拽,就使用了绝对布局,现在要给这个container添加垂直滚动条随子控件位置的改变而改变,现在虽然拖拽和滚动条都实现了,但是当双击向下拖动子控件到一定程度(拖动时顶部有一部分未显示)滚动条以后也不会显示这部分内容了。

主要修改的代码如下:

  • void CContainerUI::SetPos(RECT rc)
    {
    if( m_pVerticalScrollBar|| m_pHorizontalScrollBar)//modify 2014-11-14
    {
    CControlUI::SetPos(rc);
    rc = m_rcItem;

        // Adjust for inset
        rc.left += m_rcInset.left;
        rc.top += m_rcInset.top;
        rc.right -= m_rcInset.right;
        rc.bottom -= m_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( m_items.GetSize() == 0) {
            ProcessScrollBar(rc, 0, 0);
            return;
        }
    
        // Determine the minimum size
        SIZE szAvailable = { rc.right - rc.left, rc.bottom - rc.top };
        if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) 
            szAvailable.cx += m_pHorizontalScrollBar->GetScrollRange();
    
        // Place elements
        int cyNeeded = 0;
        int cyFixedtop = 0;
        int cyFixedbottm = 0;
        for( int it2 = 0; it2 < m_items.GetSize(); it2++ ) {
            CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);
            if( !pControl->IsVisible() ) continue;
            if( pControl->IsFloat() ) {  //modify 2014-11-14
                SetFloatPos(it2);
            }
    
            //RECT rcPadding = pControl->GetPadding();//外边距在相对布局中才有效
            RECT rt = pControl->GetPos();
            cyFixedbottm = MAX(cyFixedbottm,rt.bottom);
            cyFixedtop = MIN(cyFixedtop,rt.top);
        }
        cyNeeded = MAX(cyFixedbottm-cyFixedtop,szAvailable.cy);
    
        // Process the scrollbar
        ProcessScrollBar(rc, 0, cyNeeded);
    }
    else{
        CControlUI::SetPos(rc);
        if( m_items.IsEmpty() ) return;
        rc.left += m_rcInset.left;
        rc.top += m_rcInset.top;
        rc.right -= m_rcInset.right;
        rc.bottom -= m_rcInset.bottom;
    
        for( int it = 0; it < m_items.GetSize(); it++ ) {
            CControlUI* pControl = static_cast<CControlUI*>(m_items[it]);
            if( !pControl->IsVisible() ) continue;
            if( pControl->IsFloat() ) {
                SetFloatPos(it);
            }
            else {
                pControl->SetPos(rc); // 所有非float子控件放大到整个客户区
            }
        }
    }
    

    }

  • void CContainerUI::SetScrollPos(SIZE szPos)
    {

             ..............
    RECT rcPos;
    for( int it2 = 0; it2 < m_items.GetSize(); it2++ ) {
        CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);
        if( !pControl->IsVisible() ) continue;
        if( (!m_pVerticalScrollBar) && (!m_pHorizontalScrollBar))//modify 2014-11-14
        {
            if( pControl->IsFloat() ) 
                //SetFloatPos(it2);
                continue;
        }
        rcPos = pControl->GetPos();
        rcPos.left -= cx;
        rcPos.right -= cx;
        rcPos.top -= cy;
        rcPos.bottom -= cy;
        pControl->SetPos(rcPos);
    }
    
    Invalidate();
    

    }

  • 滚动条事件响应

  • 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_TIMER && event.wParam == SCROLL_TIMERID )//modify 2014-11-14
    {
        if( (m_uButtonState1 & UISTATE_CAPTURED) != 0 ) {
            POINT pt = m_pManager->GetMousePos();
            LONG cy = (pt.y - m_ptLastMouse.y);
            m_ptLastMouse = pt;
            SIZE sz = GetScrollPos();
            sz.cy -= cy;
            SetScrollPos(sz);
            return;
        }
        else if( m_dwDelayLeft > 0 ) {
            --m_dwDelayLeft;
            SIZE sz = GetScrollPos();
            LONG lDeltaY =  (LONG)(CalculateDelay((double)m_dwDelayLeft / m_dwDelayNum) * m_dwDelayDeltaY);
            if( (lDeltaY > 0 && sz.cy != 0)  || (lDeltaY < 0 && sz.cy != GetScrollRange().cy ) ) {
                sz.cy -= lDeltaY;
                SetScrollPos(sz);
                return;
            }
        }
        m_dwDelayDeltaY = 0;
        m_dwDelayNum = 0;
        m_dwDelayLeft = 0;
        m_pManager->KillTimer(this, SCROLL_TIMERID);
        return;
    }
    if( event.Type == UIEVENT_BUTTONDOWN && IsEnabled() )
    {
        m_uButtonState1 |= UISTATE_CAPTURED;
        m_ptLastMouse = event.ptMouse;
        m_dwDelayDeltaY = 0;
        m_dwDelayNum = 0;
        m_dwDelayLeft = 0;
        ::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_HAND)));
        m_pManager->SetTimer(this, SCROLL_TIMERID, 50U);
        //return;
    }
    if( event.Type == UIEVENT_BUTTONUP )
    {
        if( (m_uButtonState1 & UISTATE_CAPTURED) != 0 ) {
            m_uButtonState1 &= ~UISTATE_CAPTURED;
            ::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));
            if( m_ptLastMouse.y != event.ptMouse.y ) {
                m_dwDelayDeltaY = (event.ptMouse.y - m_ptLastMouse.y);
                if( m_dwDelayDeltaY > 120 ) m_dwDelayDeltaY = 120;
                else if( m_dwDelayDeltaY < -120 ) m_dwDelayDeltaY = -120;
                m_dwDelayNum = (DWORD)sqrt((double)abs(m_dwDelayDeltaY)) * 5;
                m_dwDelayLeft = m_dwDelayNum;
            }
            else 
                m_pManager->KillTimer(this, SCROLL_TIMERID);
        }
        //return;
    }
    if( event.Type == UIEVENT_SCROLLWHEEL )
    {
        LONG lDeltaY = 0;
        if( m_dwDelayNum > 0 ) lDeltaY =  (LONG)(CalculateDelay((double)m_dwDelayLeft / m_dwDelayNum) * m_dwDelayDeltaY);
        switch( LOWORD(event.wParam) ) {
            case SB_LINEUP:
                if( m_dwDelayDeltaY >= 0 ) m_dwDelayDeltaY = lDeltaY + 8;
                else m_dwDelayDeltaY = lDeltaY + 12;
                break;
            case SB_LINEDOWN:
                if( m_dwDelayDeltaY <= 0 ) m_dwDelayDeltaY = lDeltaY - 8;
                else m_dwDelayDeltaY = lDeltaY - 12;
                break;
        }
        if( m_dwDelayDeltaY > 100 ) m_dwDelayDeltaY = 100;
        else if( m_dwDelayDeltaY < -100 ) m_dwDelayDeltaY = -100;
        m_dwDelayNum = (DWORD)sqrt((double)abs(m_dwDelayDeltaY)) * 5;
        m_dwDelayLeft = m_dwDelayNum;
        m_pManager->SetTimer(this, SCROLL_TIMERID, 50U);
        return;
    }
    

直接使用HorLayout或者VerLayout就行了