• duilib中的V和H布局中滚动条问题


    转自博客:http://blog.csdn.net/damingg/article/details/41149037


    首先看一段xml代码

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
    1.  <?xml version="1.0" encoding="utf-8"?>  
    2. <Window size="300,200" caption="0,0,300,20">  
    3.     <HorizontalLayout name="aaaa" bkcolor="#FFEEEEEE" >  
    4.   
    5.         <VerticalLayout name="xxxxxx" float="true" pos="50,20,250,195" hscrollbar="true" vscrollbar="true" sepheight="4" >  
    6.           
    7.             <Label name="child1" text="text1" float="false" pos="0,0,300,200" bordercolor="#FFEE00EE" bkcolor="#FF0000EE" textcolor="#FF010101"/>  
    8.             <Label name="child2" text="text2" float="false" pos="0,0,200,200" bordercolor="#FFEE00EE" bkcolor="#FF0000EE" textcolor="#FF01FF01"/>  
    9.   
    10.         </VerticalLayout>  
    11.   
    12.     </HorizontalLayout>  
    13. </Window>  

    这是一个窗口,它包含一个竖的布局,显示出来初始状态是这样的:

    在布局中,2个子控件所需要的长和宽,比布局本身的大小要大,所以需要2个滚动条来拉动显示。

    我们可以看到横竖两个滚动条。

    不过,我们拉动滚动条,却不能完全展示子控件。如下图:

    虽然横向滚动条拉到了最右边,但Label控件child1的右边没有展示出来。

    检查代码,发现CVerticalLayoutUI的SetPos方法如下:

    1. void CVerticalLayoutUI::SetPos(RECT rc)  
    2. {  
    3.     ...省略若干代码  
    4.   
    5.     // Process the scrollbar  
    6.     ProcessScrollBar(rc, 0, cyNeeded);  
    7. }  

    在最后面,调用了基类CContainerUI的ProcessScrollBar方法,来设置滚动条信息,ProcessScrollBar函数的第二个参数是设置横向滚动条信息,第三个参数是竖向滚动条。此时设置横向的参数为0,竖向的是cyNeeded。显然,这里忽略了横向的,所以在竖向布局VerticalLayout中,横向滚动条不能正常显示。

    在CVerticalLayoutUI::SetPos中,所有涉及到cyNeeded的代码如下:

    1. int cyNeeded = 0;  
    2.         int cyExpand = 0;  
    3.         if( nAdjustables > 0 ) cyExpand = MAX(0, (szAvailable.cy - cyFixed) / nAdjustables);  
    4.         // Position the elements  
    5.         SIZE szRemaining = szAvailable;  
    6.         int iPosY = rc.top;  
    7.         if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) {  
    8.             iPosY -= m_pVerticalScrollBar->GetScrollPos();  
    9.         }  
    10.         int iPosX = rc.left;  
    11.         if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) {  
    12.             iPosX -= m_pHorizontalScrollBar->GetScrollPos();  
    13.         }  
    14.         int iAdjustable = 0;  
    15.         int cyFixedRemaining = cyFixed;  
    16.         forint it2 = 0; it2 < m_items.GetSize(); it2++ ) {  
    17.             CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);  
    18.             if( !pControl->IsVisible() ) continue;  
    19.             if( pControl->IsFloat() ) {  
    20.                 SetFloatPos(it2);  
    21.                 continue;  
    22.             }  
    23.   
    24.             RECT rcPadding = pControl->GetPadding();  
    25.             szRemaining.cy -= rcPadding.top;  
    26.             SIZE sz = pControl->EstimateSize(szRemaining);  
    27.             if( sz.cy == 0 ) {  
    28.                 iAdjustable++;  
    29.                 sz.cy = cyExpand;  
    30.                 // Distribute remaining to last element (usually round-off left-overs)  
    31.                 if( iAdjustable == nAdjustables ) {  
    32.                     sz.cy = MAX(0, szRemaining.cy - rcPadding.bottom - cyFixedRemaining);  
    33.                 }   
    34.                 if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();  
    35.                 if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();  
    36.             }  
    37.             else {  
    38.                 if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();  
    39.                 if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();  
    40.                 cyFixedRemaining -= sz.cy;  
    41.             }  
    42.   
    43.             sz.cx = pControl->GetFixedWidth();  
    44.             if( sz.cx == 0 ) sz.cx = szAvailable.cx - rcPadding.left - rcPadding.right;  
    45.             if( sz.cx < 0 ) sz.cx = 0;  
    46.             if( sz.cx < pControl->GetMinWidth() ) sz.cx = pControl->GetMinWidth();  
    47.             if( sz.cx > pControl->GetMaxWidth() ) sz.cx = pControl->GetMaxWidth();  
    48.   
    49.             RECT rcCtrl = { iPosX + rcPadding.left, iPosY + rcPadding.top, iPosX + rcPadding.left + sz.cx, iPosY + sz.cy + rcPadding.top + rcPadding.bottom };  
    50.             pControl->SetPos(rcCtrl);  
    51.   
    52.             iPosY += sz.cy + m_iChildPadding + rcPadding.top + rcPadding.bottom;  
    53.             cyNeeded += sz.cy + rcPadding.top + rcPadding.bottom;  
    54.             szRemaining.cy -= sz.cy + m_iChildPadding + rcPadding.bottom;  
    55.         }  
    56.         cyNeeded += (nEstimateNum - 1) * m_iChildPadding;  
    在for循环里,会统计所有非float子控件的高度

    在  cyNeeded += sz.cy + rcPadding.top + rcPadding.bottom;  里,sz.cy是1个子控件的高度,而rcPadding = pControl->GetPadding(); 是控件的padding属性,也就是外边距。

    最后yNeeded += (nEstimateNum - 1) * m_iChildPadding;  m_iChildPadding是布局的childpadding属性,也就是子控件之间的额外距离。

    我们可以仿照cyNeeded的计算方式,来算出cxNeeded。因为是竖向布局,所以 cyNeeded += sz.cy 这里是累加,但是横向值,应该取最宽的控件的值,

    所以for循环中的代码应该是这样:

    int tmp = sz.cx + rcPadding.left + rcPadding.right;
    cxNeeded = (tmp > cxNeeded) ? tmp: cxNeeded;

    最后cxNeeded += (nEstimateNum - 1) * m_iChildPadding;

        此时通过对代码的了解,可以得知:布局在计算容量面积时,只计算非float类型的子控件,忽略了float类型的子控件。

    算出了布局的宽度后,就应用起来

    修改原来的代码为:ProcessScrollBar(rc, cxNeeded, cyNeeded);


    改完后,发现问题依然。于是,检查了下ProcessScrollBar的代码,如下

    1. void CContainerUI::ProcessScrollBar(RECT rc, int cxRequired, int cyRequired)  
    2. {  
    3.     if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() ) {  
    4.         RECT rcScrollBarPos = { rc.left, rc.bottom, rc.right, rc.bottom + m_pHorizontalScrollBar->GetFixedHeight()};  
    5.         m_pHorizontalScrollBar->SetPos(rcScrollBarPos);  
    6.     }  
    7.   
    8.     if( m_pVerticalScrollBar == NULL ) return;  
    9.   
    10.     if( cyRequired > rc.bottom - rc.top && !m_pVerticalScrollBar->IsVisible() ) {  
    11.         m_pVerticalScrollBar->SetVisible(true);  
    12.         m_pVerticalScrollBar->SetScrollRange(cyRequired - (rc.bottom - rc.top));  
    13.         m_pVerticalScrollBar->SetScrollPos(0);  
    14.         m_bScrollProcess = true;  
    15.         SetPos(m_rcItem);  
    16.         m_bScrollProcess = false;  
    17.         return;  
    18.     }  
    19.     // No scrollbar required  
    20.     if( !m_pVerticalScrollBar->IsVisible() ) return;  
    21.   
    22.     // Scroll not needed anymore?  
    23.     int cyScroll = cyRequired - (rc.bottom - rc.top);  
    24.     if( cyScroll <= 0 && !m_bScrollProcess) {  
    25.         m_pVerticalScrollBar->SetVisible(false);  
    26.         m_pVerticalScrollBar->SetScrollPos(0);  
    27.         m_pVerticalScrollBar->SetScrollRange(0);  
    28.         SetPos(m_rcItem);  
    29.     }  
    30.     else  
    31.     {  
    32.         RECT rcScrollBarPos = { rc.right, rc.top, rc.right + m_pVerticalScrollBar->GetFixedWidth(), rc.bottom };  
    33.         m_pVerticalScrollBar->SetPos(rcScrollBarPos);  
    34.   
    35.         if( m_pVerticalScrollBar->GetScrollRange() != cyScroll ) {  
    36.             int iScrollPos = m_pVerticalScrollBar->GetScrollPos();  
    37.             m_pVerticalScrollBar->SetScrollRange(::abs(cyScroll));  
    38.             if( m_pVerticalScrollBar->GetScrollRange() == 0 ) {  
    39.                 m_pVerticalScrollBar->SetVisible(false);  
    40.                 m_pVerticalScrollBar->SetScrollPos(0);  
    41.             }  
    42.             if( iScrollPos > m_pVerticalScrollBar->GetScrollPos() ) {  
    43.                 SetPos(m_rcItem);  
    44.             }  
    45.         }  
    46.     }  
    47. }  
    很明显,cxRequired根本没有用到。

    对于横向滚动条,只使用了这3行代码:

    1. if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() ) {  
    2.     RECT rcScrollBarPos = { rc.left, rc.bottom, rc.right, rc.bottom + m_pHorizontalScrollBar->GetFixedHeight()};  
    3.     m_pHorizontalScrollBar->SetPos(rcScrollBarPos);  
    4. }  
    于是,我们需要仿照设置竖向滚动条的方式,来设置横向滚动条:

    1. void CContainerUI::ProcessScrollBar(RECT rc, int cxRequired, int cyRequired)  
    2. {  
    3.     while(m_pHorizontalScrollBar)  
    4.     {  
    5.         if (cxRequired > rc.right - rc.left && !m_pHorizontalScrollBar->IsVisible())  
    6.         {  
    7.             m_pHorizontalScrollBar->SetVisible(true);  
    8.             m_pHorizontalScrollBar->SetScrollRange(cxRequired - (rc.right - rc.left));  
    9.             m_pHorizontalScrollBar->SetScrollPos(0);  
    10.             m_bScrollProcess = true;  
    11.             SetPos(m_rcItem);  
    12.             m_bScrollProcess = false;  
    13.             break;  
    14.         }  
    15.   
    16.         if( !m_pHorizontalScrollBar->IsVisible() ) break;  
    17.   
    18.         int cxScroll = cxRequired - (rc.right - rc.left);  
    19.         if (cxScroll <= 0 && !m_bScrollProcess)  
    20.         {  
    21.             m_pHorizontalScrollBar->SetVisible(false);  
    22.             m_pHorizontalScrollBar->SetScrollPos(0);  
    23.             m_pHorizontalScrollBar->SetScrollRange(0);  
    24.             SetPos(m_rcItem);  
    25.         }  
    26.         else  
    27.         {  
    28.             RECT rcScrollBarPos = { rc.left, rc.bottom, rc.right, rc.bottom + m_pHorizontalScrollBar->GetFixedHeight() };  
    29.             m_pHorizontalScrollBar->SetPos(rcScrollBarPos);  
    30.   
    31.             if( m_pHorizontalScrollBar->GetScrollRange() != cxScroll ) {  
    32.                 int iScrollPos = m_pHorizontalScrollBar->GetScrollPos();  
    33.                 m_pHorizontalScrollBar->SetScrollRange(::abs(cxScroll));  
    34.                 if( m_pHorizontalScrollBar->GetScrollRange() == 0 ) {  
    35.                     m_pHorizontalScrollBar->SetVisible(false);  
    36.                     m_pHorizontalScrollBar->SetScrollPos(0);  
    37.                 }  
    38.                 if( iScrollPos > m_pHorizontalScrollBar->GetScrollPos() ) {  
    39.                     SetPos(m_rcItem);  
    40.                 }  
    41.             }  
    42.         }  
    43.         break;  
    44.     }  
    45.   
    46.     while(m_pVerticalScrollBar)  
    47.     {  
    48.         if( cyRequired > rc.bottom - rc.top && !m_pVerticalScrollBar->IsVisible() ) {  
    49.             m_pVerticalScrollBar->SetVisible(true);  
    50.             m_pVerticalScrollBar->SetScrollRange(cyRequired - (rc.bottom - rc.top));  
    51.             m_pVerticalScrollBar->SetScrollPos(0);  
    52.             m_bScrollProcess = true;  
    53.             SetPos(m_rcItem);  
    54.             m_bScrollProcess = false;  
    55.             break;  
    56.         }  
    57.         // No scrollbar required  
    58.         if( !m_pVerticalScrollBar->IsVisible() ) break;  
    59.   
    60.         // Scroll not needed anymore?  
    61.         int cyScroll = cyRequired - (rc.bottom - rc.top);  
    62.         if( cyScroll <= 0 && !m_bScrollProcess) {  
    63.             m_pVerticalScrollBar->SetVisible(false);  
    64.             m_pVerticalScrollBar->SetScrollPos(0);  
    65.             m_pVerticalScrollBar->SetScrollRange(0);  
    66.             SetPos(m_rcItem);  
    67.         }  
    68.         else  
    69.         {  
    70.             RECT rcScrollBarPos = { rc.right, rc.top, rc.right + m_pVerticalScrollBar->GetFixedWidth(), rc.bottom };  
    71.             m_pVerticalScrollBar->SetPos(rcScrollBarPos);  
    72.   
    73.             if( m_pVerticalScrollBar->GetScrollRange() != cyScroll ) {  
    74.                 int iScrollPos = m_pVerticalScrollBar->GetScrollPos();  
    75.                 m_pVerticalScrollBar->SetScrollRange(::abs(cyScroll));  
    76.                 if( m_pVerticalScrollBar->GetScrollRange() == 0 ) {  
    77.                     m_pVerticalScrollBar->SetVisible(false);  
    78.                     m_pVerticalScrollBar->SetScrollPos(0);  
    79.                 }  
    80.                 if( iScrollPos > m_pVerticalScrollBar->GetScrollPos() ) {  
    81.                     SetPos(m_rcItem);  
    82.                 }  
    83.             }  
    84.         }  
    85.         break;  
    86.     }  
    87. }  

    看看效果

    可以看到控件child1的右边框。


    HorizontalLayout也有同样的问题,可类似修改。

  • 相关阅读:
    [Swift]LeetCode300. 最长上升子序列 | Longest Increasing Subsequence
    备忘录模式之C++实现
    leecode 题解 || Merge k Sorted Lists 问题
    数学三大危机
    singlefile.py
    Data Url生成工具之HTML5 FileReader实现
    算法题:打印1到最大的n位数
    java.lang.NoClassDefFoundError: org/apache/commons/lang/xwork/StringUtils
    hdu 1181 变形课
    postgis经常使用函数介绍(一)
  • 原文地址:https://www.cnblogs.com/redrainblog/p/4136194.html
Copyright © 2020-2023  润新知