duilib消息机制剖析最小化后用哪个消息通知恢复

&&&&&&&&&&&&&&&&&&
posts - 108,comments - 4,trackbacks - 0
在中已经知道了如何将窗体显示出来,而如何处理窗体上的事件、消息呢?
一. 系统消息
窗体显示的时候我们就已经说了,窗体是继承CWindowWnd类的,对于窗体的部分消息的处理,需要重载该类的LRESULT&HandleMessage(UINT&uMsg,&WPARAM&wParam,&LPARAM&lParam);&函数。在显示窗体部分我们创建窗体WM_CREATE消息以及屏蔽标题栏WM_NCACTIVATE、WM_NCCALCSIZE、WM_NCPAINT等消息&都是在HandleMessage中进行处理:
LRESULT CMainWndDlg::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam )
LRESULT lRes = 0;
BOOL bHandled = TRUE;
switch( uMsg )
case WM_CREATE:
lRes = OnCreate(uMsg, wParam, lParam, bHandled);
case WM_NCACTIVATE:
lRes = OnNcActivate(uMsg, wParam, lParam, bHandled);
case WM_NCCALCSIZE:
lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled);
case WM_NCPAINT:
lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break;
case WM_NCHITTEST:
lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;
case WM_CLOSE:
lRes = OnClose(uMsg, wParam, lParam, bHandled); break;
case WM_DESTROY:
lRes = OnDestroy(uMsg, wParam, lParam, bHandled); break;
case WM_SIZE:
lRes = OnSize(uMsg, wParam, lParam, bHandled); break;
case WM_GETMINMAXINFO: lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); break;
case WM_SYSCOMMAND:
lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break;
case WM_KEYDOWN:
PostQuitMessage(0); break;
bHandled = FALSE;
if( bHandled ) return lR
if( m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes) ) return lR
return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
如同代码中所示,如果消息不需要框架再处理了则直接返回。如果还需要框架处理该消息,则交由父类的HandleMessge中去处理。
二. 事件消息
对于系统消息我们直接重载了HandleMessage来处理,而对于鼠标点击一类的消息呢?为此,我们的窗体除了要继承CWindowWnd外,还需要继承INotifyUI,同样的重载INotifyUI类中的void&Notify(TNotifyUI&&msg);&函数,由该函数来处理控件操作产生的消息。但仅仅只是继承重载了还不够,我们怎么才能确保事件消息能正常传递呢?因此,在窗体创建OnCreate的时候,我们还需要添加如下m_PaintManager.AddNotifier(this);&这样,控件消息就可以传达大duilib的消息循环中,我们也就可以通过Notify函数对消息进行处理:
void CMainWndDlg::Notify( TNotifyUI& msg )
if( msg.sType == _T("windowinit") ) {
OnWindowInit();
else if( msg.sType == _T("click") ) {
if( msg.pSender == m_pCloseBtn ) {
PostQuitMessage(0);
else if( msg.pSender == m_pMinBtn ) {
SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0); return; }
else if( msg.pSender == m_pMaxBtn ) {
SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0); return; }
else if( msg.pSender == m_pRestoreBtn ) {
SendMessage(WM_SYSCOMMAND, SC_RESTORE, 0); return; }
// 按钮消息
OnLBtnClick(msg.pSender);
else if(msg.sType==_T("selectchanged"))
CDuiString name = msg.pSender-&GetName();
CTabLayoutUI* pTabSwitch = static_cast&CTabLayoutUI*&(m_PaintManager.FindControl(_T("tab_switch")));
CTabLayoutUI* pDemoListSwitch = static_cast&CTabLayoutUI*&(m_PaintManager.FindControl(_T("demo_list_tab_switch")));
if(pareNoCase(_T("demo_tab")) == 0)
pTabSwitch-&SelectItem(0);
else if(pareNoCase(_T("web_tab")) == 0)
pTabSwitch-&SelectItem(1);
if(pareNoCase(_T("demo_list_basic_ctrl")) == 0)
pDemoListSwitch-&SelectItem(0);
else if(pareNoCase(_T("demo_list_rich_ctrl")) == 0)
pDemoListSwitch-&SelectItem(1);
在Notify函数中针对消息的不同进行不同的操作处理,比如click、selectchanged等等。对于这类duilib针对相关操作自定义的消息类型可以在duilib工程中的UIDefine.h文件中查看:
//定义所有消息类型
//////////////////////////////////////////////////////////////////////////
#define DUI_MSGTYPE_MENU
(_T("menu"))
#define DUI_MSGTYPE_LINK
(_T("link"))
#define DUI_MSGTYPE_TIMER
(_T("timer"))
#define DUI_MSGTYPE_CLICK
(_T("click"))
#define DUI_MSGTYPE_RETURN
(_T("return"))
#define DUI_MSGTYPE_SCROLL
(_T("scroll"))
#define DUI_MSGTYPE_DROPDOWN
(_T("dropdown"))
#define DUI_MSGTYPE_SETFOCUS
(_T("setfocus"))
#define DUI_MSGTYPE_KILLFOCUS
(_T("killfocus"))
#define DUI_MSGTYPE_ITEMCLICK
(_T("itemclick"))
#define DUI_MSGTYPE_TABSELECT
(_T("tabselect"))
#define DUI_MSGTYPE_ITEMSELECT
(_T("itemselect"))
#define DUI_MSGTYPE_ITEMEXPAND
(_T("itemexpand"))
#define DUI_MSGTYPE_WINDOWINIT
(_T("windowinit"))
#define DUI_MSGTYPE_BUTTONDOWN
(_T("buttondown"))
#define DUI_MSGTYPE_MOUSEENTER
(_T("mouseenter"))
#define DUI_MSGTYPE_MOUSELEAVE
(_T("mouseleave"))
#define DUI_MSGTYPE_TEXTCHANGED
(_T("textchanged"))
#define DUI_MSGTYPE_HEADERCLICK
(_T("headerclick"))
#define DUI_MSGTYPE_ITEMDBCLICK
(_T("itemdbclick"))
#define DUI_MSGTYPE_SHOWACTIVEX
(_T("showactivex"))
#define DUI_MSGTYPE_ITEMCOLLAPSE
(_T("itemcollapse"))
#define DUI_MSGTYPE_ITEMACTIVATE
(_T("itemactivate"))
#define DUI_MSGTYPE_VALUECHANGED
(_T("valuechanged"))
#define DUI_MSGTYPE_SELECTCHANGED
(_T("selectchanged"))
//////////////////////////////////////////////////////////////////////////
三. 消息过滤
在实际中,我们有时候可能需要根据需要对部分消息进行分类处理。比如键盘按键消息等等。对于这类情况,我们的窗体需要继承IMessageFilterUI类,重载LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled)函数,同时在窗体OnCreate创建的时候添加m_pm_.AddPreMessageFilter(this)消息通知即可。
阅读(...) 评论()转载请说明原出处,谢谢~~
& & & &&我在前一段时间研究了怎么制作duilib的菜单,花了几天时间以MenuDemo为基础做出个duilib的菜单以备自用,近些天在群里经常会碰到群友问如何给MenuDemo增加消息响应,为了避免重复的回答我特意写这篇日志,希望可以帮到需要之人,同时也介绍了如何美化菜单的效果、动态修改自身的状态以及通过增加属性来优化菜单的xml文件编写过程,先截个图展示一下效果。
本菜单的优点如下:
& & & & 1、可以展现多级菜单
& & & &&2、可内嵌自定义控件,并且控件可以向主窗体发送消息,如图的红色叹号就是个按钮控件,可以制作酷狗音乐的托盘菜单的播放暂停按钮和进度控制进度条。
& & & &&3、菜单拥有阴影效果
& & & &&4、菜单可以自定义前方显示小图标,并且可以控制图标的大小和是否显示
& & & &&5、菜单可以根据是否拥有子菜单决定是否显示小箭头
& & & &&6、菜单可以添加分割线
& & & &&7、每个菜单项都可以实现check菜单的功能,而且check信息会被保存下来以备下次显示
& & & &&8、优化菜单的xml描述文件,编写方便容易,如果要写一个二级菜单,比如编写图片中的菜单测试4以及他的子菜单,只需如下代码就可以了
& & & &&9、可以通过键盘的按钮控制菜单的选项
& & & &&10、每个菜单项的高度宽度是任意调整的
&MenuElement text="菜单测试4" icon="right.png" iconsize="9,9" expland="true" &
&MenuElement text="菜单测试5" expland="true" icon="WebSit.png" iconsize="16,16"&
&MenuElement text="菜单测试6"
icon="Virus.png" iconsize="16,16"/&
&MenuElement text="菜单测试7" /&
&/MenuElement&
&MenuElement text="菜单测试8" expland="true"&
&MenuElement text="菜单测试a" /&
&MenuElement text="菜单测试b" /&
&/MenuElement&
&/MenuElement&
& & & &&菜单介绍完了,先说说我的开发过程的准备阶段。
& & & &&大家知道duilib库是个非常棒的开源库,我个人很喜欢他,但是由于现在作者不维护了,导致现在库中存在的bug无人料理,控件也相对不足,而菜单控件是软件开发中常用的,duilib库中虽然给出了MenuDemo,但是没有增加消息响应,导致一些朋友不会使用他,我开始也是这样,所以打算自己给duilib做一个菜单。
& & & &&我接触到的和duilib有关的菜单的例子有:原带的MenuDemo、Alberl写的简易Menu、ListDemo中的MenuWnd、其他库的已经编写成熟的Menu.
& & & &&我找了很多Menu的代码,看了看他们的实现方法。我在这里简单的说一下他们的优缺点:
& & & &&原带的MenuDemo:
& & & &&优点:1、实现了多级菜单
& & & &&& & & &&2、内嵌自定义控件
& & & &&缺点:1、无消息响应功能
& & & &&& & & &&2、菜单的xml描述文件过于繁琐,在其中实现小箭头或者小图标都要靠自己的布局来实现,这点大家可以看他的xml文件。
& & & &&Alberl写的简易Menu和ListDemo中的MenuWnd:
& & & &&优点:1、使用简单方便
& & && 2、外观效果很好
& & & &&缺点:1、只是一级菜单,无法满足很多需要多级菜单的场合
& & &&2、没有封装为菜单类,无法通过调节属性来控制菜单的效果
& & &&3、菜单的逻辑和消息处理比较简单,逻辑效果不够完善
总结了他们的优缺点之后,我打算做出个更通用的菜单,更简单,效果更好的菜单,他拥有多级菜单、内嵌自定义控件、可以实现消息响应、外
观效果要好、可以通过简单的xml文件描述就把菜单编写出来、可以显示小图标和小箭头、菜单内实现check的功能,并且可以把是否被check的信息
保存下来。
& & & &&现在说一下我的编写过程,开始我想自己写一个菜单,但是我写到一半的时候就被难倒了,由于我个人水平的限制。多级菜单的实现我一直无法完美搞定,看似简单的东西,其实里面包含很多逻辑判断:多级菜单的显示位置,显示大小,如何通知上级菜单自己被销毁,怎么发送通知,何时销毁自己,应该显示那个下级菜单,怎么保存子菜单的信息。实在搞不下去我只好去求救于现成的MenuDemo,他的最大优点就是已经写好的多级菜单的逻辑,而且并不需要再修改这部分逻辑,而这正是我认为最难实现的部分,所以我就直接在MenuDemo的基础上进行下一步开发,作者用观察者模式很好的实现了这个功能,前人栽树后人乘凉,在此谢过编写MenuDemo的作者。
& & & &&接下在我先吧多数人最关心的怎么发送并响应菜单的消息的部分说明一下。
& & & &&要实现消息响应有三种方法:1、通过给菜单增加Notify接口实现 &2、通过给菜单项增加委托实现 &3、通过系统的消息机制实现
& & & &&实际上第一种和第二种的方法是类似的,而第三种方法最麻烦但是效果和性能是做好的。
& & & &&我先介绍第一种和第二种方法
& & & &&通过读MenuDemo的代码可以知道,菜单实际上是一个弹出窗体,既然我们的主窗体可以响应控件的消息,那么这个弹出窗体同样可以实现,我们要做到就是在菜单类CMenuWnd中继承消息通知接口INotifyUI,这样PaintManager类就会在合适的时候把消息发送到继承了这个接口的窗体上,我们要在CMenuWnd类中实现Notify函数,这个大家应该很熟悉,然后我们在CMenuWnd类的HandleMessage函数的WM_CREATE消息处理中增加这个代码,m_pm.AttachDialog(pRoot);(如果不知道在哪里添加,可以搜索语句m_pm.AttachDialog(pRoot);,在这句代码下添加,记住有两处需要添加),增加了这个代码后PaintManager类在发现消息后就会把这个消息分发到拥有Notify函数的窗体中,这样我们就能在CMenuWnd类的Notify函数中接收到菜单被单击的消息了,这个处理方法大家应该很熟悉的。(PS:ListDemo就是用这个方法来处理消息,如果还不会的朋友可以看一下他的代码)
& & & &&第二种方法是通过委托,这是模仿c#的功能,实际上也就是通过巧妙的回调函数实现的技术。当我们创建了菜单后,在CMenuUI类的Add和AddAt函数中增加类似这样的代码:
& & & &&pMenuItem-&OnNotify&+= MakeDelegate(this, &CMenuUI::OnMenuElemrntClick);
& & & &&然后我们在CMenuUI类中增加这种形式的函数bool Fn(void*);比如例子中的函数为bool&OnMenuElemrntClick(void*
prarm);函数体如下
bool OnMenuElemrntClick(void* param)
TNotifyUI* pMsg = (TNotifyUI*)
if( pMsg-&sType == _T("itemclick"))
//处理消息
& & & &&这样就能接收到消息,接收到消息后就是如何把消息发送到主窗体让他来处理消息,为此我们要在主窗体创建菜单时把任意一个控件的指针传到菜单里面,然后菜单里保存这个指针,比如为m_pOwner,然后在Notify函数或者OnMenuElemrntClick函数里,首先判断出是单击了那个菜单项,然后使用如下代码把消息发送到主窗体:
if( m_pOwner )
m_pOwner-&GetManager()-&SendNotify(m_pOwner, _T("菜单消息"), 0, 0, true);
& & & &&回到主窗体,在主窗体的Notify函数里就可以接收到这个消息了,接收的demo如下
if( msg.sType == _T("菜单消息") ) {
//收到了菜单的消息
& & & &&至此,第一种和第二种方法就介绍完了,我最开始就是使用这个方法发送消息的,但是注意这个方法有缺陷:不能在主窗体的接收函数中做出会导致菜单销毁的事情,比如最常见的弹出Messagebox或者模式窗体,否则程序会崩溃。原因很简单,因为首先是菜单发送消息给主窗体,然后主窗体收到消息,但是注意这是菜单还有剩余代码没有执行完,如果这时弹出模式窗体,菜单就会因为失去焦点而销毁,等到弹出的模式窗体销毁后,程序会执行菜单里没有执行完的代码,但是此时菜单已经被销毁,所以程序就崩溃了,切记!
第三种方法
& & & &&这是我现在使用的也是推荐给大家的方法,就是使用系统的消息机制来将菜单项的单击发送给主窗体,这个方法快速有效,而且没有第一种和第
二种方法的缺陷。
& & & &&首先我们在菜单类的头文件中自定义一个小,比如我的是
#define WM_MENUCLICK WM_USER +121
//用来接收按钮单击的消息
& & & &&然后我们在CMenuElementUI类的每一个响应单击的位置加上这句代码
&span style="font-family: Arial, Helvetica, sans-"&PostMessage(s_context_menu_observer.m_hMainWnd, WM_MENUCLICK, (WPARAM)(new CDuiString(GetName().GetData())), &/span&&span style="font-family: Arial, Helvetica, sans-"&(LPARAM)0&/span&&span style="font-family: Arial, Helvetica, sans-"&);&/span&
& & & & 这样就把消息发送到主窗体,为此我们需要在菜单建立时把主窗体的句柄传进来并且保存,我把这个句柄保存到了s_context_menu_observer,
因为他是原demo自带的一个全局变量,很好的满足 了我们的需求。这里注意我是把菜单的Name传送了过去而不是传送ID,这符合duilib的使用习惯。
注意传送字符串我使用了new,在处理了字符串后一定要记得delete他,否则会内存泄漏!
接着我们在主窗体里接收这个消息,只要我们的窗体是继承自WindowImplBase类,我们就可以在窗体类中重写HandleCustomMessage函数,这
个函数本意就是让我们来操作自定义消息的,如果不是继承自WindowImplBase类,那就直接在HanddlMessage函数里响应了。收到了这个消息,想怎
么处理都随你了。
至此,我就介绍完了最关键的怎么响应消息的部分,我做得那个菜单同时使用了第一种和第三种方法,用第一种方法来发送自动一控件的消息,比
如播放被单击;用第三种方法来传递菜单项的单击消息,这样菜单的消息传送就完全了。
& & & &&优化代码和显示效果
& & & &&可以看到MenuDemo的xml文件的编写实在是复杂难懂,他只是提供了个容器,里面显示的内容完全要靠自己的布局来完成,这样过于繁琐,所以
我通过增加属性的方法简化了这个过程,可以在文章的篇头看到我的那个xml代码比原demo的xml少多了。
& & & &&为了减少代码量,我给菜单项增加了icon、 iconsize、ischeck、expland四个属性,分别控制显示的小图标,图标的大小、是否被选中,是否可以
展开。然后在类中增加了相应的函数,用来绘制小图标,扩展图标,绘制的时候要根据自己所在的菜单项的高度宽度和自己的大小来调整合适的位置,
还有改不改绘制出来。这样子就简化了xml的编写,不过说起来简单,我做的时候在处理小图标和扩展图标的显示的先后顺序上也花了点时间,估计是
自己的逻辑还不够清晰。
& & & &&另外我还增加了一个属性"type",当属性值为"line"时, 就绘制一条横线,绘制的横线的颜色、宽度等信息是从菜单的Default标签中获取的。
& & & &&接着为了给菜单增加阴影效果,我使用了CShadowWnd类,这个类的用法和demo我在多个duilib群里都上传过,就不再赘述了。
& & & &&最后再说一下动态修改自己的状态,为了给菜单增加check的功能,我们要保存下来每个菜单项的check状态,而菜单每次都是重新创建的,所以
这个状态信息不能在菜单本身保存,我在主窗体中声明一个map&CDuiString,bool&模版的变量用来保存菜单项的状态,第一个字段保存菜单的名称,
用来区别不同的菜单项,第二个字段来区分菜单是否被选中,创建菜单时这个变量传进去,然后让菜单自己来维护这个变量,当菜单项被单击时,他会
从变量中找到自己并且修改为应有的值,菜单在创建时会读取这个变量找到自己的信息来决定是否绘制小图标。
& & & &&至此,我的这篇日志就结束了,我大致把自己实现这个菜单的思路讲了一下,但是由于我的个人水平的原因,可能代码逻辑并不好,我的说明也
不够清晰。如果你有什么建议,非常欢迎给我提出来,可以加我QQ,也可以留言。我打算今天再把我做的菜单重构一下,把绘制图形的代码重新整理
一下,让他更高效。希望可以帮到需要的朋友!
& & & & & 附上窗体阴影的代码和Demo:
&10:41 &Redrain
阅读(...) 评论()duilib List控件,横向滚动时列表项不移动或者显示错位的bug的修复 -
- ITkeyowrd
duilib List控件,横向滚动时列表项不移动或者显示错位的bug的修复
转载请说明出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/关于这个bug的修复我之前写过一篇博客,连接为:http://blog.csdn.net/zhuhongshu/article/details/本以为已经修复好,但是后来有网友私聊我,反映到还存在bug。原本已经解决的bug如下:1.当List出现滚动条后,拖动滚动条,这时ListContainElementUI控件内部的子控件跟随Header自动调节位置会有差错,明显看到偏移不正确2.当List出现滚动条后,拖动滚动条到任意位置让ListContainElementUI控件内部的子控件位移,然后最小化窗体再恢复。发现本应该发生偏移的子控件这时却跑到了原位。新的bug是:当List出现滚动条后,拖动滚动条到任意位置让ListContainElementUI控件内部的子控件位移,然后最大化窗体,就发现列表项的偏移不正确,再次恢复后的列表项位置也有问题。尝试从ListContainElementUI控件的SetPos函数解决问题,发现总是无法十全十美,没办法既顾及到最小化又顾及最大化,同时还要计算偏移。尝试修复几个小时都不成功。回头想想,前面的三个问题的根源都在于,List容器先重新计算列表项的位置,再去计算表头的位置。而列表项要根据表头的位置去自适应。之前的做法一直是在列表项调整位置时去尝试计算表头的位置,而这样做的致命缺点就是,当最小化和最大化后表头的位置会有突然的变化而知道计算失误。换个思路,只要让列表先计算表头的位置,再去计算列表项的位置,自然就没问题了。······,感觉以前的思路好傻。通过这个思路可以简单有效的修复所有bug,之前的文章的修复过程全部作废,bug的修复过程如下:修复过程:一、List控件的SetPos函数源码如下:void CListUI::SetPos(RECT rc){ CVerticalLayoutUI::SetPos(rc);if( m_pHeader == NULL )// Determine general list information and the size of header columnsm_ListInfo.nColumns = MIN(m_pHeader-&GetCount(), UILIST_MAX_COLUMNS);// The header/columns may or may not be visible at runtime. In either case// we should determine the correct dimensions...if( !m_pHeader-&IsVisible() ) {for( int it = 0; it & m_pHeader-&GetCount(); it++ ) {static_cast&CControlUI*&(m_pHeader-&GetItemAt(it))-&SetInternVisible(true);}m_pHeader-&SetPos(CDuiRect(rc.left, 0, rc.right, 0));}int iOffset = m_pList-&GetScrollPos().for( int i = 0; i & m_ListInfo.nC i++ ) {CControlUI* pControl = static_cast&CControlUI*&(m_pHeader-&GetItemAt(i));if( !pControl-&IsVisible() )if( pControl-&IsFloat() )RECT rcPos = pControl-&GetPos();if( iOffset & 0 ) {rcPos.left -= iOrcPos.right -= iOpControl-&SetPos(rcPos);}m_ListInfo.rcColumn[i] = pControl-&GetPos();}if( !m_pHeader-&IsVisible() ) {for( int it = 0; it & m_pHeader-&GetCount(); it++ ) {static_cast&CControlUI*&(m_pHeader-&GetItemAt(it))-&SetInternVisible(false);}}}代码里首先调用父类的SetPos函数,在父类的SetPos里面会初始化表头和列表项的位置,然后可以看到List的SetPos根据滚动条的位置重新调整了表头的位置。首先要在函数的最后加入这句代码来重新计算列表项的位置: m_pList-&SetPos(m_pList-&GetPos());二、当横向滚动条控件移动时,会通知父控件已经移动来让父控件做出响应。也就是列表滚动条控件会调用List的SetScrollPos函数,而List控件的SetScrollPos函数会调用CListBodyUI控件的SetScrollPos函数,CListBodyUI控件是所有列表项的容器。在CListBodyUI控件的SetScrollPos函数里,先计算了列表项的位置,后计算表头的位置。所以修改对应代码的位置就可以了,修改后的代码如下:void CListBodyUI::SetScrollPos(SIZE szPos){int cx = 0;int cy = 0;if( m_pVerticalScrollBar && m_pVerticalScrollBar-&IsVisible() ) {int iLastScrollPos = m_pVerticalScrollBar-&GetScrollPos();m_pVerticalScrollBar-&SetScrollPos(szPos.cy);cy = m_pVerticalScrollBar-&GetScrollPos() - iLastScrollP}if( m_pHorizontalScrollBar && m_pHorizontalScrollBar-&IsVisible() ) {int iLastScrollPos = m_pHorizontalScrollBar-&GetScrollPos();m_pHorizontalScrollBar-&SetScrollPos(szPos.cx);cx = m_pHorizontalScrollBar-&GetScrollPos() - iLastScrollP}if( cx == 0 && cy == 0 ) if( cx != 0 && m_pOwner ) {CListHeaderUI* pHeader = m_pOwner-&GetHeader();if( pHeader == NULL )TListInfoUI* pInfo = m_pOwner-&GetListInfo();pInfo-&nColumns = MIN(pHeader-&GetCount(), UILIST_MAX_COLUMNS);if( !pHeader-&IsVisible() ) {for( int it = 0; it & pHeader-&GetCount(); it++ ) {static_cast&CControlUI*&(pHeader-&GetItemAt(it))-&SetInternVisible(true);}}for( int i = 0; i & pInfo-&nC i++ ) {CControlUI* pControl = static_cast&CControlUI*&(pHeader-&GetItemAt(i));if( !pControl-&IsVisible() )if( pControl-&IsFloat() )RECT rcPos = pControl-&GetPos();rcPos.left -=rcPos.right -=pControl-&SetPos(rcPos);pInfo-&rcColumn[i] = pControl-&GetPos();}if( !pHeader-&IsVisible() ) {for( int it = 0; it & pHeader-&GetCount(); it++ ) {static_cast&CControlUI*&(pHeader-&GetItemAt(it))-&SetInternVisible(false);}} }RECT rcPfor( int it2 = 0; it2 & m_items.GetSize(); it2++ ) {CControlUI* pControl = static_cast&CControlUI*&(m_items[it2]);if( !pControl-&IsVisible() )if( pControl-&IsFloat() )rcPos = pControl-&GetPos();rcPos.left -=rcPos.right -=rcPos.top -=rcPos.bottom -=pControl-&SetPos(rcPos);}Invalidate();}三、当表头的位置计算好后,最后修改ListContainElementUI的SetPos函数去计算他的子控件的位置,代码比以前的版本简单了很多:void CListContainerElementUI::SetPos(RECT rc){CHorizontalLayoutUI::SetPos(rc); if( m_pOwner == NULL )CListUI* pList = static_cast&CListUI*&(m_pOwner); if (pList == NULL) CListHeaderUI *pHeader = pList-&GetHeader(); if (pHeader == NULL || !pHeader-&IsVisible())int nCount = m_items.GetSize(); for (int i = 0; i & nC i++) {CControlUI *pListItem = static_cast&CControlUI*&(m_items[i]);CControlUI *pHeaderItem = pHeader-&GetItemAt(i);if (pHeaderItem == NULL)RECT rcHeaderItem = pHeaderItem-&GetPos();if (pListItem != NULL && !(rcHeaderItem.left ==0 && rcHeaderItem.right ==0) ){RECT rt = pListItem-&GetPos();rt.left =rcHeaderItem.rt.right = rcHeaderItem.pListItem-&SetPos(rt);} }}总结:有这个修复代码后,以前的文章的修复代码就作废了。如果要修改ListContainElementUI的朋友可以根据我上面给出的代码修改,也可以直接下载我自己的Duilib库。我的Duilib库代码下载地址:点击打开链接Redrain
转载请说明出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/
关于这个bug的修复我之前写过一篇博客,连接为:http://blog.csdn.net/zhuhongshu/article/d
相关阅读排行
相关内容推荐
请激活账号
为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。
您的注册邮箱:
如果您没有收到激活邮件,请注意检查垃圾箱。

我要回帖

更多关于 duilib 消息映射 的文章

 

随机推荐