duilib List控件,横向滚动时列表项不移动或者移动错位的bug的修复
转载请说明出处,谢谢~~
这篇博客已经作废,只是留作记录,新的bug修复博客地址:http://blog.csdn.net/zhuhongshu/article/details/42264673
之前就在群里挺群友朋友说道,使用List控件,里面加入ListContainElementUI元素,当List出现横向滚动条时,滚动条滑动后元素不跟着滑动或者滑动后位置不正确。
关于List控件的扩展,很早就有人做过了:
http://blog.csdn.net/xdrt81y/article/details/17790203
http://blog.csdn.net/tragicguy/article/details/21893065
里面提到了,改造List的Header为容器的方法,和让ListContainElementUI控件内部的子控件跟随Header自动调节位置的方法。不过实际测试后会发现还是有问题的。我先把问题描述一下:
1.当List出现滚动条后,拖动滚动条,这时ListContainElementUI控件内部的子控件跟随Header自动调节位置会有差错,明显看到偏移不正确
2.当List出现滚动条后,拖动滚动条到任意位置让ListContainElementUI控件内部的子控件位移,然后最小化窗体再恢复。发现本应该发生偏移的子控件这时却跑到了原位。
这篇文章里我会把这些问题都分析一下原因,并且给出解决方法。
分析过程:
ListContainElementUI控件无疑是List元素中使用最多的,因为他本身就是个容器,可以存放任意元素,拥有极大的灵活性。如果要让他内部的子控件跟随Header自动调整位置,那么我们应该重写他的SetPos函数来控制子控件。这里引入我前面例举的第二篇博文的代码:
void CListContainerElementUI::SetPos(RECT rc)
{
CContainerUI::SetPos(rc);
if( m_pOwner == NULL ) return; if (m_pHeader == NULL)
{
return;
}
TListInfoUI* pInfo = m_pOwner->GetListInfo();
int nCount = m_items.GetSize();
for (int i = 0; i < nCount; i++)
{
CControlUI *pHorizontalLayout = static_cast<CControlUI*>(m_items[i]); CListHeaderItemUI *pHeaderItem = static_cast<CListHeaderItemUI*>(m_pHeader->GetItemAt(i));
if (pHorizontalLayout != NULL && pHeaderItem != NULL)
{
RECT rtHeader = pHeaderItem->GetPos();
RECT rt = pHorizontalLayout->GetPos();
rt.left = rtHeader.left;
rt.right = rtHeader.right;
pHorizontalLayout->SetPos(rt);
}
}
}
在SetPos函数里,动态获取Header,然后根据Header的位置再去调整子控件的位置。这段代码在不出现横向滚动条的时候是正常使用了,但是出现横向滚动条后滚动的效果就会出现偏差。
导致这个问题的原因是,List控件的会先调用各个元素的SetPos函数,然后重新计算Header的位置,这时ListContainElementUI的SetPos里得到的Header的位置还是久位置,所以导致了最后显示的位置错乱。这里的解决方法就是自己去计算新的偏移差。新的代码如下:
void CListContainerElementUI::SetPos(RECT rc)
{
CContainedUI::SetPos(rc);
if( m_pOwner == NULL ) return; CListUI* pList = static_cast<CListUI*>(m_pOwner);
if (pList == NULL) return; TListInfoUI* pInfo = pList->GetListInfo();
CListHeaderUI* pHeader = pList->GetHeader();
int nNewCxPos = pList->GetScrollPos().cx; int nOffset = nNewCxPos - m_nOldCxPos; int nCount = m_items.GetSize();
for (int i = 0; i < nCount; i++)
{
CControlUI *pListItem = static_cast<CControlUI*>(m_items[i]); CListHeaderItemUI *pHeaderItem = static_cast<CListHeaderItemUI*>(pHeader->GetItemAt(i));
if (pListItem != NULL && pHeaderItem != NULL)
{
RECT rtHeader = pHeaderItem->GetPos();
RECT rt = pListItem->GetPos();
rt.left = rtHeader.left - nOffset;
rt.right = rtHeader.right - nOffset;
pListItem->SetPos(rt);
} } m_nOldCxPos = nNewCxPos;
}
这里获取了List的横向滚动条的滚动值,然后计算出偏移,为此我们需要为ListContainElementUI增加一个int 型的m_nOldCxPos变量来记录偏移值。这时就解决了第一个问题,子控件的位置可以随Header精确移动。
但是,却会出现第二个问题,窗体最小化然后恢复后原本应该位移的子控件却恢复到初始位置。我调试后发现是Header的位置计算出现了问题,所以导致了这个问题。仔细看了List自带的各个成员变量,后来发现通过List的GetListInfo函数获取的TListInfoUI结构里面的RECT数组rcColumn可以获取到Header正确的数值,因为我们调用ListContainElementUI的SetPos时List还没有将错误的Header数值保存到rcColumn里面,所以修改SetPos代码如下:
void CListContainerElementUI::SetPos(RECT rc)
{
CContainerUI::SetPos(rc);
if( m_pOwner == NULL ) return; CListUI* pList = static_cast<CListUI*>(m_pOwner);
if (pList == NULL) return; TListInfoUI* pInfo = pList->GetListInfo();
int nNewCxPos = pList->GetScrollPos().cx; int nExcursion = nNewCxPos - m_nOldCxPos; int nCount = m_items.GetSize();
for (int i = 0; i < nCount; i++)
{
CControlUI *pListItem = static_cast<CControlUI*>(m_items[i]); if (pListItem != NULL )
{
RECT rt = pListItem->GetPos();
rt.left = pInfo->rcColumn[i].left - nExcursion;
rt.right = pInfo->rcColumn[i].right - nExcursion;
pListItem->SetPos(rt);
}
} m_nOldCxPos = nNewCxPos;
}
这时两个问题都解决了,但是同时导致了新的问题:当程序初始化后第一次显示界面,ListContainElementUI的子控件全部都是隐藏的。原因是我们这里使用了rcColumn来计算子控件的位置,而程序初始化时rcColumn里面的值都是0,所以导致了错误计算。所以需要加上判断,如果rcColumn里面的值为0则不计算位置,这样就好了。但是还有问题:初始化后ListContainElementUI的控件虽然都显示了,但是都重叠到一起了。导致这个问题的原因是ListContainElementUI虽然是容器,但是他继承的是CContainerUI容器,他没有自动排列子控件的功能。所以我这里让ListContainElementUI继承CHorizontalLayoutUI容器。这样还能方便我们以后编写对应的xml代码。
给出最终的修改代码:
void CListContainerElementUI::SetPos(RECT rc)
{
CHorizontalLayoutUI::SetPos(rc);
if( m_pOwner == NULL ) return; CListUI* pList = static_cast<CListUI*>(m_pOwner);
if (pList == NULL) return; TListInfoUI* pInfo = pList->GetListInfo();
int nNewCxPos = pList->GetScrollPos().cx; int nExcursion = nNewCxPos - m_nOldCxPos; int nCount = m_items.GetSize();
for (int i = 0; i < nCount; i++)
{
CControlUI *pListItem = static_cast<CControlUI*>(m_items[i]); if (pListItem != NULL && pInfo->rcColumn[i].left != 0 && pInfo->rcColumn[i].right != 0)
{
RECT rt = pListItem->GetPos();
rt.left = pInfo->rcColumn[i].left - nExcursion;
rt.right = pInfo->rcColumn[i].right - nExcursion;
pListItem->SetPos(rt);
}
} m_nOldCxPos = nNewCxPos;
}
总结:
如果要修改ListContainElementUI的朋友可以根据我上面给出的代码修改,也可以直接下载我自己的Duilib库。
我把我自己使用的Duilib和Uilib库都上传到了GitHub,完整的Duilib库代码下载地址:点击打开链接
这是我自己使用的Duilib和Uilib库,修复了我在博客中说明的所有bug以及很多还没有去说明的bug,同样也包含别人修复过的bug。库里面包含我扩展过的部分控件。以及添加了Duilib扩展群群主heat的透明异形窗体功能的支持。
这个库是我用vs2010修改的。如果你无法正常打开我的库或者编译有问题,那么建议把你需要的.h或者.cpp文件替换你自己的duilib库对应的文件。
我修改过的代码,一般可以通过搜索“redrain”找到对应的位置和修改时间
此库是我个人使用,由于我水平所限,所以不保证我修改的代码的质量。请你看过代码后再决定是否使用。使用这个库出现问题,不承担任何责任。
Redrain 2014.10.30
duilib List控件,横向滚动时列表项不移动或者移动错位的bug的修复的更多相关文章
- duilib List控件,横向滚动时列表项不移动或者显示错位的bug的修复
转载请说明出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42264673 关于这个bug的修复我之前写过一篇博客,连接为:http:/ ...
- duilib combo控件,当鼠标滚动时下拉列表自动关闭的bug的修复
转载请说明出处,谢谢~~ 群里有朋友提到了使用Combo控件时,当下拉列表出现,此时鼠标滚轮滚动,下拉列表就自动消失了.我看了一下源码,这个bug的修复很简单. CComboUI控件被单击时创建CCo ...
- iOS 9应用开发教程之使用开关滑块控件以及滚动部署视图
iOS 9应用开发教程之使用开关滑块控件以及滚动部署视图 使用ios9中的开关.滑块控件 开关和滑块也是用于和用户进行交互的控件.本节将主要讲解这两种控件. ios9开关 开关控件常用来控制某个功能的 ...
- Winform禁止容器内控件获得焦点时改变容器显示范围坐标
在Winform中当容器的可视高度无法显示所有控件并且容器的AutoScroll属性设置为True的情况下,但点击容器内某个未显示完整的控件时,会出现容器的滚动条自动下滚的情况. 这是由于控件获得焦点 ...
- 五种情况下会刷新控件状态(刷新所有子FWinControls的显示)——从DFM读取数据时、新增加子控件时、重新创建当前控件的句柄时、设置父控件时、显示状态被改变时
五种情况下会刷新控件状态(刷新控件状态才能刷新所有子FWinControls的显示): 在TWinControls.PaintControls中,对所有FWinControls只是重绘了边框,而没有整 ...
- DS控件库 Win7链接列表框的仿Windows开始菜单样式
Win7链接列表框是依照Windows7的开始菜单开发的,同时进行了属性和功能的扩展. 效果图 项属性 控件属性 控件主要事件 点击项(Sender As Win7链接列表框, Itm As 链接项, ...
- Qt在控件未显示时如何获取正确的控件尺寸
因为打算全屏显示一个对话框,而对话框内有几个QLabel的尺寸要在确定QLabel可用的最大尺寸后,再根据内容调整一次,所以在对话框构造函数内就想确定QLabel的最大尺寸,但因为QWidget::u ...
- 关于使用UniForm以其他控件为Parent时应该注意的问题
关于使用UniForm以其他控件为Parent时应该注意的问题: 1,不能在其他组件的oncreate,onbeforeshow,onshow等事件中来生成这样的uniform,否则其上的组件不能显示 ...
- WPF控件获得焦点时去除虚线框
原文:WPF控件获得焦点时去除虚线框 <Setter Property="FocusVisualStyle" Value="{x:Null}" />
随机推荐
- cojs 疯狂的魔法树 疯狂的颜色序列 题解报告
疯狂的魔法树 一个各种操作大杂烩的鬼畜数据结构题目 首先我们注意到树的形态是半随机的 我们可以树分块,对树分成若干个块 对于每个块我们维护一个add标记表示增量 维护一个vis标记表示覆盖量 注意标记 ...
- 李洪强iOS开发之让您的Xcode键字如飞
手指在键盘上飞速跳跃,终端上的代码也随着飞舞,是的这确实很酷.优秀的程序员总是这么一群人,他们不拘于现状,不固步自封,他们喜欢新奇的事,他们把自己发挥到极致. 指法攻略 放下您钟爱的鼠标吧,在前行之中 ...
- Project Euler 86:Cuboid route 长方体路径
Cuboid route A spider, S, sits in one corner of a cuboid room, measuring 6 by 5 by 3, and a fly, F, ...
- *[hackerrank]ACM ICPC Team
https://www.hackerrank.com/contests/w6/challenges/acm-icpc-team 这道题在contest的时候数据量改小过,原来的数据量需要进行优化才能过 ...
- Windows下Subversion和Apache的安装及配置(一)
1.序 Subversion可谓版本控制软件中的佼佼者,其开源性,易用性已受到众多软件开发者首选的版本控制软件.在这里我想记录我安装Subversion和Apache的过程.注意,Subversion ...
- ADO.NET基础02(语句参数化,配置文件,DataSet与DataTable)
ADO.NET连接池 ado.net默认启用了连接池 *如何清空连接池?Connection的静态方法ClearAllPools(). ClearPool() Ado.net连接池使用总结: 1.第一 ...
- python基础 - 文件读写
完成功能: 从指定位置读文件到控制台 #! /usr/bin/python # coding=utf- 方法一. try: f = open ('/root/python/file/001.txt', ...
- Help And Manual 帮助文件制作工具
Help And Manual 简 介 帮助文件制作工具 支持文件格式 26种 其他功能 制作非常专业的使用手册 一个所见即所得的帮助文件制作工具,是市面上功能最强的 WYSIWYG (所见即所 ...
- TCP digest
TCP在网络OSI的七层模型中的第四层——Transport层,IP在第三层——Network层,ARP在第二层——Data Link层,在第二层上的数据,我们叫Frame,在第三层上的数据叫Pack ...
- 对于接收到的GPS信息详解
最近一直在做gps驱动方面的东西,对于底层接收到的gps信息不是很了解,查询了资料对这些信息做出总结: 由于在室内,所以信号不是很好,接收不到卫星信号,必须站到窗口或者空旷的地方,这是gps的debu ...