duilib中的V和H布局中滚动条问题
转自博客:http://blog.csdn.net/damingg/article/details/41149037
首先看一段xml代码
- <?xml version="1.0" encoding="utf-8"?>
- <Window size="300,200" caption="0,0,300,20">
- <HorizontalLayout name="aaaa" bkcolor="#FFEEEEEE" >
- <VerticalLayout name="xxxxxx" float="true" pos="50,20,250,195" hscrollbar="true" vscrollbar="true" sepheight="4" >
- <Label name="child1" text="text1" float="false" pos="0,0,300,200" bordercolor="#FFEE00EE" bkcolor="#FF0000EE" textcolor="#FF010101"/>
- <Label name="child2" text="text2" float="false" pos="0,0,200,200" bordercolor="#FFEE00EE" bkcolor="#FF0000EE" textcolor="#FF01FF01"/>
- </VerticalLayout>
- </HorizontalLayout>
- </Window>
这是一个窗口,它包含一个竖的布局,显示出来初始状态是这样的:
在布局中,2个子控件所需要的长和宽,比布局本身的大小要大,所以需要2个滚动条来拉动显示。
我们可以看到横竖两个滚动条。
不过,我们拉动滚动条,却不能完全展示子控件。如下图:
虽然横向滚动条拉到了最右边,但Label控件child1的右边没有展示出来。
检查代码,发现CVerticalLayoutUI的SetPos方法如下:
- void CVerticalLayoutUI::SetPos(RECT rc)
- {
- ...省略若干代码
- // Process the scrollbar
- ProcessScrollBar(rc, 0, cyNeeded);
- }
在最后面,调用了基类CContainerUI的ProcessScrollBar方法,来设置滚动条信息,ProcessScrollBar函数的第二个参数是设置横向滚动条信息,第三个参数是竖向滚动条。此时设置横向的参数为0,竖向的是cyNeeded。显然,这里忽略了横向的,所以在竖向布局VerticalLayout中,横向滚动条不能正常显示。
在CVerticalLayoutUI::SetPos中,所有涉及到cyNeeded的代码如下:
- int cyNeeded = 0;
- int cyExpand = 0;
- if( nAdjustables > 0 ) cyExpand = MAX(0, (szAvailable.cy - cyFixed) / nAdjustables);
- // Position the elements
- SIZE szRemaining = szAvailable;
- int iPosY = rc.top;
- if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) {
- iPosY -= m_pVerticalScrollBar->GetScrollPos();
- }
- int iPosX = rc.left;
- if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) {
- iPosX -= m_pHorizontalScrollBar->GetScrollPos();
- }
- int iAdjustable = 0;
- int cyFixedRemaining = cyFixed;
- for( int it2 = 0; it2 < m_items.GetSize(); it2++ ) {
- CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);
- if( !pControl->IsVisible() ) continue;
- if( pControl->IsFloat() ) {
- SetFloatPos(it2);
- continue;
- }
- RECT rcPadding = pControl->GetPadding();
- szRemaining.cy -= rcPadding.top;
- SIZE sz = pControl->EstimateSize(szRemaining);
- if( sz.cy == 0 ) {
- iAdjustable++;
- sz.cy = cyExpand;
- // Distribute remaining to last element (usually round-off left-overs)
- if( iAdjustable == nAdjustables ) {
- sz.cy = MAX(0, szRemaining.cy - rcPadding.bottom - cyFixedRemaining);
- }
- if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();
- if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();
- }
- else {
- if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();
- if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();
- cyFixedRemaining -= sz.cy;
- }
- sz.cx = pControl->GetFixedWidth();
- if( sz.cx == 0 ) sz.cx = szAvailable.cx - rcPadding.left - rcPadding.right;
- if( sz.cx < 0 ) sz.cx = 0;
- if( sz.cx < pControl->GetMinWidth() ) sz.cx = pControl->GetMinWidth();
- if( sz.cx > pControl->GetMaxWidth() ) sz.cx = pControl->GetMaxWidth();
- RECT rcCtrl = { iPosX + rcPadding.left, iPosY + rcPadding.top, iPosX + rcPadding.left + sz.cx, iPosY + sz.cy + rcPadding.top + rcPadding.bottom };
- pControl->SetPos(rcCtrl);
- iPosY += sz.cy + m_iChildPadding + rcPadding.top + rcPadding.bottom;
- cyNeeded += sz.cy + rcPadding.top + rcPadding.bottom;
- szRemaining.cy -= sz.cy + m_iChildPadding + rcPadding.bottom;
- }
- 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的代码,如下
- void CContainerUI::ProcessScrollBar(RECT rc, int cxRequired, int cyRequired)
- {
- if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() ) {
- RECT rcScrollBarPos = { rc.left, rc.bottom, rc.right, rc.bottom + m_pHorizontalScrollBar->GetFixedHeight()};
- m_pHorizontalScrollBar->SetPos(rcScrollBarPos);
- }
- if( m_pVerticalScrollBar == NULL ) return;
- if( cyRequired > rc.bottom - rc.top && !m_pVerticalScrollBar->IsVisible() ) {
- m_pVerticalScrollBar->SetVisible(true);
- m_pVerticalScrollBar->SetScrollRange(cyRequired - (rc.bottom - rc.top));
- m_pVerticalScrollBar->SetScrollPos(0);
- m_bScrollProcess = true;
- SetPos(m_rcItem);
- m_bScrollProcess = false;
- return;
- }
- // No scrollbar required
- if( !m_pVerticalScrollBar->IsVisible() ) return;
- // Scroll not needed anymore?
- int cyScroll = cyRequired - (rc.bottom - rc.top);
- if( cyScroll <= 0 && !m_bScrollProcess) {
- m_pVerticalScrollBar->SetVisible(false);
- m_pVerticalScrollBar->SetScrollPos(0);
- m_pVerticalScrollBar->SetScrollRange(0);
- SetPos(m_rcItem);
- }
- else
- {
- RECT rcScrollBarPos = { rc.right, rc.top, rc.right + m_pVerticalScrollBar->GetFixedWidth(), rc.bottom };
- m_pVerticalScrollBar->SetPos(rcScrollBarPos);
- if( m_pVerticalScrollBar->GetScrollRange() != cyScroll ) {
- int iScrollPos = m_pVerticalScrollBar->GetScrollPos();
- m_pVerticalScrollBar->SetScrollRange(::abs(cyScroll));
- if( m_pVerticalScrollBar->GetScrollRange() == 0 ) {
- m_pVerticalScrollBar->SetVisible(false);
- m_pVerticalScrollBar->SetScrollPos(0);
- }
- if( iScrollPos > m_pVerticalScrollBar->GetScrollPos() ) {
- SetPos(m_rcItem);
- }
- }
- }
- }
很明显,cxRequired根本没有用到。
对于横向滚动条,只使用了这3行代码:
- if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() ) {
- RECT rcScrollBarPos = { rc.left, rc.bottom, rc.right, rc.bottom + m_pHorizontalScrollBar->GetFixedHeight()};
- m_pHorizontalScrollBar->SetPos(rcScrollBarPos);
- }
于是,我们需要仿照设置竖向滚动条的方式,来设置横向滚动条:
- void CContainerUI::ProcessScrollBar(RECT rc, int cxRequired, int cyRequired)
- {
- while(m_pHorizontalScrollBar)
- {
- if (cxRequired > rc.right - rc.left && !m_pHorizontalScrollBar->IsVisible())
- {
- m_pHorizontalScrollBar->SetVisible(true);
- m_pHorizontalScrollBar->SetScrollRange(cxRequired - (rc.right - rc.left));
- m_pHorizontalScrollBar->SetScrollPos(0);
- m_bScrollProcess = true;
- SetPos(m_rcItem);
- m_bScrollProcess = false;
- break;
- }
- if( !m_pHorizontalScrollBar->IsVisible() ) break;
- int cxScroll = cxRequired - (rc.right - rc.left);
- if (cxScroll <= 0 && !m_bScrollProcess)
- {
- m_pHorizontalScrollBar->SetVisible(false);
- m_pHorizontalScrollBar->SetScrollPos(0);
- m_pHorizontalScrollBar->SetScrollRange(0);
- SetPos(m_rcItem);
- }
- else
- {
- RECT rcScrollBarPos = { rc.left, rc.bottom, rc.right, rc.bottom + m_pHorizontalScrollBar->GetFixedHeight() };
- m_pHorizontalScrollBar->SetPos(rcScrollBarPos);
- if( m_pHorizontalScrollBar->GetScrollRange() != cxScroll ) {
- int iScrollPos = m_pHorizontalScrollBar->GetScrollPos();
- m_pHorizontalScrollBar->SetScrollRange(::abs(cxScroll));
- if( m_pHorizontalScrollBar->GetScrollRange() == 0 ) {
- m_pHorizontalScrollBar->SetVisible(false);
- m_pHorizontalScrollBar->SetScrollPos(0);
- }
- if( iScrollPos > m_pHorizontalScrollBar->GetScrollPos() ) {
- SetPos(m_rcItem);
- }
- }
- }
- break;
- }
- while(m_pVerticalScrollBar)
- {
- if( cyRequired > rc.bottom - rc.top && !m_pVerticalScrollBar->IsVisible() ) {
- m_pVerticalScrollBar->SetVisible(true);
- m_pVerticalScrollBar->SetScrollRange(cyRequired - (rc.bottom - rc.top));
- m_pVerticalScrollBar->SetScrollPos(0);
- m_bScrollProcess = true;
- SetPos(m_rcItem);
- m_bScrollProcess = false;
- break;
- }
- // No scrollbar required
- if( !m_pVerticalScrollBar->IsVisible() ) break;
- // Scroll not needed anymore?
- int cyScroll = cyRequired - (rc.bottom - rc.top);
- if( cyScroll <= 0 && !m_bScrollProcess) {
- m_pVerticalScrollBar->SetVisible(false);
- m_pVerticalScrollBar->SetScrollPos(0);
- m_pVerticalScrollBar->SetScrollRange(0);
- SetPos(m_rcItem);
- }
- else
- {
- RECT rcScrollBarPos = { rc.right, rc.top, rc.right + m_pVerticalScrollBar->GetFixedWidth(), rc.bottom };
- m_pVerticalScrollBar->SetPos(rcScrollBarPos);
- if( m_pVerticalScrollBar->GetScrollRange() != cyScroll ) {
- int iScrollPos = m_pVerticalScrollBar->GetScrollPos();
- m_pVerticalScrollBar->SetScrollRange(::abs(cyScroll));
- if( m_pVerticalScrollBar->GetScrollRange() == 0 ) {
- m_pVerticalScrollBar->SetVisible(false);
- m_pVerticalScrollBar->SetScrollPos(0);
- }
- if( iScrollPos > m_pVerticalScrollBar->GetScrollPos() ) {
- SetPos(m_rcItem);
- }
- }
- }
- break;
- }
- }
看看效果
可以看到控件child1的右边框。
HorizontalLayout也有同样的问题,可类似修改。
duilib中的V和H布局中滚动条问题的更多相关文章
- ios中fixed元素在滚动布局中的延时渲染问题
在之前做的一个demo中,有个视图是内滚动的,里边有个bar用了fixed,不是fixed在最外层视图的顶部和底部,在微信/safari/chrome/其他浏览器app上都没出现问题. 然后今天,我把 ...
- 【转】在Android布局中使用include和merge标签
内容转自:http://fengweipeng1208.blog.163.com/blog/static/21277318020138229754135/ 在我们开发android布局时,经常会有很多 ...
- 在网页布局中合理使用inline formating context(IFC)
引子:给大家出一个小小的考题,如何使用css来实现类似下面的在指定区域内,内容自适应的垂直居中.
- 使用ViewSwitcher和ViewFlipper在不同布局中切换
xml布局: <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:androi ...
- 摘:C/C++中时间类time.h
摘要:本文从介绍基础概念入手,探讨了在C/C++中对日期和时间操作所用到的数据结构和函数,并对计时.时间的获取.时间的计算和显示格式等方面进行了阐述.本文还通过大量的实例向你展示了time.h头文件中 ...
- vivo前端智能化实践:机器学习在自动网页布局中的应用
作者:vivo 互联网前端团队- Su Ning 在设计稿转网页中运用基于self-attention机制设计的机器学习模型进行设计稿的布局,能够结合dom节点的上下文得出合理的方案. 一.背景 切图 ...
- 在布局中使用android.support.v4.app.Fragment的注意事项
1.Activity必须继承android.support.v4.app.FragmentActivity 2.fragment标签的name属性必须是完全限定包名,如下: <LinearLay ...
- DIV+CSS布局中主要CSS属性介绍
Float: Float属性是DIV+CSS布局中最基本也是最常用的属性,用于实现多列功能,我们知道<div>标签默认一行只能显示一个,而使用Float属性可以实现一行显示多个div的功能 ...
- 响应式web布局中iframe的自适应
困境 在响应式布局中,我们应该小心对待iframe元素,iframe元素的width和height属性设置了其宽度和高度,但是当包含块的宽度或高度小于iframe的宽度或高度时,会出现iframe元素 ...
随机推荐
- keystonejs
开始之前先确保你已经安装了Node.js 0.10+ 和MongoDB v2.4+. 要使用KeystoneJS,你需要掌握合理的Javascript知识,并熟悉数据库概念之类的基础知识,会用 nod ...
- 入门视频采集与处理(BT656简介)
入门视频采集与处理(BT656简介) http://ticktick.blog.51cto.com/823160/553535 1. 帧的概念(Frame) 一个视频序列是由N个帧组成的,采集图像的 ...
- mysql表的一对一/一对多/多对多联系
1.数据库中的多对多关联关系一般需采用中间表的方式处理,将多对多转化为两个一对多. 2.通过表的关系,来帮助我们怎样建表,建几张表. 一对一 一张表的一条记录一定只能与另外一张表的一条记录进行对应,反 ...
- 2014-9-17二班----6 web project
部署 加载 到 Tomcat 6.0 服务器上 web.xml <welcome>index.jsp </welcome> <welcome&g ...
- 234. Palindrome Linked List
题目: Given a singly linked list, determine if it is a palindrome. Follow up:Could you do it in O(n) t ...
- 确认某端口占用情况并结束相应进程(Windows)
(1)确认某端口是否被占用 (2)通过查找对应的PID号,定位是哪一个进程在使用该端口 (3)通过PID号结束该进程 # 查找端口2000是否被占用C:\Users\tdcqma>netstat ...
- Filter设计实现IP地址限制
示例:创建一个IP过滤Filter,当一个用户发出访问请求的时候,首先通过过滤器进行判断, 如果用户的IP地址被限制,就禁止访问,只有合法的IP才可以继续访问.IP过滤Filter代码如下: IPFi ...
- 遍历并remove HashMap中的元素时,遇到ConcurrentModificationException
遍历并remove HashMap中的元素时,遇到ConcurrentModificationException for (Map.Entry<ImageView, UserConcise> ...
- Tomcat的SessionID引起的Session Fixation和Session Hijacking问题
上一篇说到<Spring MVC防御CSRF.XSS和SQL注入攻击>,今天说说SessionID带来的漏洞攻击问题.首先,什么是Session Fixation攻击和Session Hi ...
- ER模型到关系模型的转换规则
E-R模型向关系模型的转换规则: 一.两元联系的转换规则 (1)实体类型的转换 将每个实体类型转换成一个关系模式,实体的属性即为关系的属性,实体标识符即为关系的键. (2)联系类型的转换 a实体间的联 ...
