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

时间: 2024-08-01 08:22:07

duilib List控件,横向滚动时列表项不移动或者移动错位的bug的修复的相关文章

duilib List控件,横向滚动时列表项不移动或者显示错位的bug的修复

转载请说明出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42264673         关于这个bug的修复我之前写过一篇博客,连接为:http://blog.csdn.net/zhuhongshu/article/details/40622705         本以为已经修复好,但是后来有网友私聊我,反映到还存在bug.原本已经解决的bug如下:         1.当List出现滚动条后,拖动滚动条,这时ListConta

duilib combo控件,当鼠标滚动时下拉列表自动关闭的bug的修复

转载请说明出处,谢谢~~       群里有朋友提到了使用Combo控件时,当下拉列表出现,此时鼠标滚轮滚动,下拉列表就自动消失了.我看了一下源码,这个bug的修复很简单.       CComboUI控件被单击时创建CComboWnd窗体来模拟下拉菜单.CComboWnd类在HandleMessage函数里处理了鼠标滚动消息WM_MOUSEWHEEL,他把这个消息转发给CComboUI的DoEvent函数去处理,而CComboUI的DoEvent函数处理对应的UIEVENT_SCROLLWHE

为ASP.NET控件添加设计时支持

asp.net|控件|设计 简介 Microsoft ASP.NET 为开发人员提供了一种适用于 Web 开发的.功能最为强大的新工具:服务器控件.服务器控件使开发人员能够在短时间内开发出响应速度快而且功能强大的 Web 应用程序,所需的时间与在典型的 ASP 中创建类似应用程序的时间差不多. ASP.NET 服务器控件之所以能够提供生产效率,关键原因之一在于它为 Microsoft Visual Studio .NET 开发环境中的服务器控件提供了丰富的设计时支持.开发人员可以将服务器控件从

Android中实现HorizontalScrollView内子控件横向拖拽

前言 网上ListView上下拖动的例子有,效果也很好,但是项目要横着拖的,只要硬着头皮自己写(主要是没找到合适的),参考文章1修改而来,分享一下. 截图 代码 java public class HoDragActivity extends Activity { private LinearLayout main; private GestureDetector mGestureDetector; @Override public void onCreate(Bundle savedInsta

仿listBox写了一个Control控件为item的列表集合

  仿listBox写了一个Control控件为item的列表集合,由于最近做个项目要用,微软提供的控件实现起来不行,但自己写了一个,效果如下: 代码   1using System;  2using System.Collections.Generic;  3using System.ComponentModel;  4using System.Data;  5using System.Drawing;  6using System.Text;  7using System.Text.Regu

WinForm控件开发总结(十一) 调试控件的设计时行为

前面的一些文章绝大部分都是要讲控件的设计时的行为,既然涉及到这么多的设计时行为的代码编写 ,那么就有必要就一下如何来调试控件的设计行为. 调试控件的设计时行为和调试DLL的方式非常的相似,因为DLL是不能够单独运行的,而一般的控件也 会在一个DLL里.当然如果你不考虑类的可复用性而把控件写在一个Windows Application里面也无可厚非 ,这样调试倒也变的简单了.但是我们还是要考虑更通常的情况.一般来说,我们调试DLL时,都是创建 一个可独立运行的应用程序,在这个应用程序里引用你希望调

100个chart控件实时绘图时,单击单个chart控件显示每个chart控件的放大曲线时总是滞后

问题描述 100个chart控件实时绘图时,单击单个chart控件显示每个chart控件的放大曲线时总是滞后 我有100个chart控件组成的数据采集界面,一段时间要对这100个单独的chart控件进行数据绘图,单独点击某一个chart控件还能看到每一个chart控件的放大曲线图,遇到的问题就是:恰好在对100个chart控件同时进行绘图时,此时单击任何一个chart控件都会卡住,只到100个chart的绘图过程结束,单个chart的放大界面曲线才能看到,有什么办法能让这两个过程互不影响吗?线程

duilib如何控件flash播放速度?

问题描述 duilib如何控件flash播放速度? 想请教大神位一下:duilib如何控件flash的播放速度啊?谢谢了! 解决方案 可以api hook拦截gettickcount并且修改,类似变速齿轮 解决方案二: 可以api hook拦截gettickcount并且修改,类似变速齿轮 解决方案三: c++控件播放flash

【求助】怎么静止webbrowser控件刷新网页时的加载声音

问题描述 [求助]怎么静止webbrowser控件刷新网页时的加载声音 如题,做了一个用到了webbrowser的软件,需要刷新或者加载,但是加载了或者刷新了就会有加载的那个声音,要怎么屏蔽掉这个声音而且不影响其他的声音呢