修复duilib库UISlider控件的4个bug
转载级请注明原出处,谢谢~·
昨天封装好一个音频类,我在为dulib做音频播放demo时发现了一些问题,由CSliderUI控件导致的,进而发现了这个控件的好几样不足,他无法满
足我们做一个播放器的进度控件和音量控制控件,具体问题如下:
//=====================================================================================================
2014.7.28 redrain修改,QQ:491646717,有疑问或者bug2请联系我
修改的代码的DoEvent部分的逻辑借鉴和复制了网友 快樂每一天(群昵称 花落半歌,QQ:848861075 )的代码
问题说明:我正在制作仿酷狗播放器,做到音乐播放的部分时用到CSliderUI控件,后台的音频类回去控制CSliderUI的行为 CSliderUI的行为与酷狗的很不一样,有几样缺陷:
问题1:只能通过点击CSliderUI的某个位置才能触发valuechanged消息,无法通过滑动滑块去触发,这个bug最严重
问题2:点击CSliderUI的某个位置,当鼠标弹起时滑块才改变位置,而其他软件都是鼠标按下时就改变了
问题3:后台有代码一直调用SetValue函数改变滑块的位置时,会和鼠标土洞滑块冲突,表现在滑块会一直来回跳动
问题4:滑块滑动过程中无法通知主窗体正在改变,这点用在音量改变时,通常我们是一边滑动一边就改变了音量,而不是滑动完成后再改, 为
此我们添加一个新的消息DUI_MSGTYPE_VALUECHANGED_MOVE,把这个消息的定义放到UIDefine.h文件中
#define DUI_MSGTYPE_VALUECHANGED_MOVE (_T("movevaluechanged"))
同时出于效率考虑,要让CSliderUI发出这个消息,应该设置属性sendmove为真,默认为假
我修改的代码可以通过搜索字符串“2014.7.28 redrain”,来查找,方便大家查看源码
此次修改不会影响控件原有的属性,我个人水平有限,如果有任何问题,可以联系我
//=====================================================================================================
问题的描述结束了,其中的大部分问题都是由于在DoEvent函数中对一些逻辑的判断的不足导致的。
问题1的解决:只能通过点击CSliderUI的某个位置才能触发valuechanged消息,无法通过滑动滑块去触发这是由于原来的UIEVENT_BUTTONUP
消息处理不当造成的,原代码为:
if( event.Type == UIEVENT_BUTTONUP )
{
int nValue;
if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) {
m_uButtonState &= ~UISTATE_CAPTURED;
}
if( m_bHorizontal ) {
if( event.ptMouse.x >= m_rcItem.right - m_szThumb.cx / 2 ) nValue = m_nMax;
else if( event.ptMouse.x <= m_rcItem.left + m_szThumb.cx / 2 ) nValue = m_nMin;
else nValue = m_nMin + (m_nMax - m_nMin) * (event.ptMouse.x - m_rcItem.left - m_szThumb.cx / 2 ) / (m_rcItem.right - m_rcItem.left - m_szThumb.cx);
}
else {
if( event.ptMouse.y >= m_rcItem.bottom - m_szThumb.cy / 2 ) nValue = m_nMin;
else if( event.ptMouse.y <= m_rcItem.top + m_szThumb.cy / 2 ) nValue = m_nMax;
else nValue = m_nMin + (m_nMax - m_nMin) * (m_rcItem.bottom - event.ptMouse.y - m_szThumb.cy / 2 ) / (m_rcItem.bottom - m_rcItem.top - m_szThumb.cy);
}
if(m_nValue !=nValue && nValue>=m_nMin && nValue<=m_nMax)
{
m_nValue =nValue;
m_pManager->SendNotify(this, DUI_MSGTYPE_VALUECHANGED);
Invalidate();
}
return;
}
在最后的判断出可以看到,只有当m_nValue !=nValue时才会发送DUI_MSGTYPE_VALUECHANGED消息,而我们滑动滑块时,通过上面的代码
不难分析出,
这两个值一直是相等的,所以导致他没有发出消息,所以我们把这个判断注释掉就行了
问题2的解决:
点击CSliderUI的某个位置,当鼠标弹起时滑块才改变位置,而其他软件都是鼠标按下时就改变了,这是由于原来的UIEVENT_BUTTONDOWN
消
息的处理不全面造成的,原代码为:
if( event.Type == UIEVENT_BUTTONDOWN || event.Type == UIEVENT_DBLCLICK )
{
if( IsEnabled() ) {
RECT rcThumb = GetThumbRect();
if( ::PtInRect(&rcThumb, event.ptMouse) ) {
m_uButtonState |= UISTATE_CAPTURED;
}
}
return;
}
可以看到原代码没有做对于控件的外观的任何修改,我们把代码修改如下:
if( event.Type == UIEVENT_BUTTONDOWN || event.Type == UIEVENT_DBLCLICK )
{
if( IsEnabled() ) {//2014.7.28 redrain 注释掉原来的代码,加上这些代码后可以让Slider不是在鼠标弹起时才改变滑块的位置
m_uButtonState |= UISTATE_CAPTURED; int nValue; if( m_bHorizontal ) {
if( event.ptMouse.x >= m_rcItem.right - m_szThumb.cx / 2 ) nValue = m_nMax;
else if( event.ptMouse.x <= m_rcItem.left + m_szThumb.cx / 2 ) nValue = m_nMin;
else nValue = m_nMin + (m_nMax - m_nMin) * (event.ptMouse.x - m_rcItem.left - m_szThumb.cx / 2 ) / (m_rcItem.right - m_rcItem.left - m_szThumb.cx);
}
else {
if( event.ptMouse.y >= m_rcItem.bottom - m_szThumb.cy / 2 ) nValue = m_nMin;
else if( event.ptMouse.y <= m_rcItem.top + m_szThumb.cy / 2 ) nValue = m_nMax;
else nValue = m_nMin + (m_nMax - m_nMin) * (m_rcItem.bottom - event.ptMouse.y - m_szThumb.cy / 2 ) / (m_rcItem.bottom - m_rcItem.top - m_szThumb.cy);
}
if(m_nValue !=nValue && nValue>=m_nMin && nValue<=m_nMax)
{
m_nValue =nValue;
Invalidate();
}
}
return;
}
问题3的解决:
后台有代码一直调用SetValue函数改变滑块的位置时,会和鼠标土洞滑块冲突,表现在滑块会一直来回跳动,这是因为,当我们拖动滑块时会动
态的修改Slider的m_nValue值,并且会刷新控件,而通过读PaintStatusImage函数可知,控件正式通过这个m_nValue变量来决定滑块的绘制位置。而
我在后台让音乐播放类去根据音乐的进度调用SetValue函数,这个函数理所当然的修改了m_nValue值,这就导致了冲突,这个函数是父类的,所以我
们要重写这个函数。当鼠标正在滑动式不让SetValue去改变控件的滑块的位置。
增加SetValue函数然后重写他,修改的代码为:
void CSliderUI::SetValue(int nValue)
{
if( (m_uButtonState & UISTATE_CAPTURED) != 0 )
return;
CProgressUI::SetValue(nValue);
}
问题4的解决:
滑块滑动过程中无法通知主窗体正在改变,这点用在音量改变时,通常我们是一边滑动一边就改变了音量,而不是滑动完成后再改变, 为此我们
添加一个新的消息DUI_MSGTYPE_VALUECHANGED_MOVE,把这个消息的定义放到UIDefine.h文件中,这个代码只要在DoEvent的UIEVENT_MOUS
EMOVE消息处理中把DUI_MSGTYPE_VALUECHANGED_MOVE事件传送出去就好了,后来听从网友“不乖打Pp.”的建议,增加了一个属性"sendmove"
,当属行为真时才发送消息出去。
修改代码为:
if( event.Type == UIEVENT_MOUSEMOVE )
{
if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) {
if( m_bHorizontal ) {
if( event.ptMouse.x >= m_rcItem.right - m_szThumb.cx / 2 ) m_nValue = m_nMax;
else if( event.ptMouse.x <= m_rcItem.left + m_szThumb.cx / 2 ) m_nValue = m_nMin;
else m_nValue = m_nMin + (m_nMax - m_nMin) * (event.ptMouse.x - m_rcItem.left - m_szThumb.cx / 2 ) / (m_rcItem.right - m_rcItem.left - m_szThumb.cx);
}
else {
if( event.ptMouse.y >= m_rcItem.bottom - m_szThumb.cy / 2 ) m_nValue = m_nMin;
else if( event.ptMouse.y <= m_rcItem.top + m_szThumb.cy / 2 ) m_nValue = m_nMax;
else m_nValue = m_nMin + (m_nMax - m_nMin) * (m_rcItem.bottom - event.ptMouse.y - m_szThumb.cy / 2 ) / (m_rcItem.bottom - m_rcItem.top - m_szThumb.cy);
}
if (m_bSendMove)
m_pManager->SendNotify(this, DUI_MSGTYPE_VALUECHANGED_MOVE);
Invalidate();
} if( !m_bMouseTracking ) {
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.hwndTrack = m_pManager->GetPaintWindow();
tme.dwHoverTime =400UL;
_TrackMouseEvent(&tme);
m_bMouseTracking = true;
}
// Generate the appropriate mouse messages
POINT pt = event.ptMouse;
RECT rcThumb = GetThumbRect();
if( IsEnabled() && ::PtInRect(&rcThumb, event.ptMouse) ) { m_uButtonState |= UISTATE_HOT;
Invalidate();
}else
{
m_uButtonState &= ~UISTATE_HOT;
Invalidate();
}
return;
}
至此我们就修改了四处地方,还有其他修改的地方大家可以自己看源文件,此次修改不会影响控件原有的属性,我个人水平有限,如果有任何问
题,可以联系我。
patch的下载地址:http://download.csdn.net/detail/zhuhongshu/7686617
2014.7.28 13:14 Redrain
修复duilib库UISlider控件的4个bug的更多相关文章
- 改进duilib的richedit控件的部分功能
转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41208207 如果要使用透明异形窗体功能,首先要改进duilib库让他本 ...
- 将webkit内核封装为duilib的浏览器控件
转载请说明出处,谢谢~~ 原本的duilib是自带浏览器控件的,但是使用了IE内核,我在做仿酷狗音乐播放器时,在右侧乐库要用到浏览器控件,而我使用自带的IE控件却发现了不少缺点,这也是duilib一直 ...
- 基于Qt的第三方库和控件
====================== 基于Qt的第三方库和控件 ====================== libQxt -------- http://dev.libqxt.o ...
- Duilib教程-控件练习
一.控件消息的响应. 在HelloDuilib例子中,程序不能退出,在这里,我将添加一个关闭按钮,当点击它时,调用PostQuitMessage进行退出. 首先在界面的右上角添加一个关闭按钮,并取名为 ...
- bootstrap课程13 bootstrap的官方文档中有一些控件的使用有bug,如何解决这个问题
bootstrap课程13 bootstrap的官方文档中有一些控件的使用有bug,如何解决这个问题 一.总结 一句话总结:因为演示是正常的,所以检查演示效果的代码,把那一段相关的都弄过来就可以了 ...
- duilib 绘制IP控件
在使用duilib时,发现本来的库并没有提供IP控件,如是自己想到绘制IP控件,控件的绘制不难,首先赋值UIEdit的两个文件,命名为UIIPEdit,更改完成后,便可以进行修改绘制IP控件. 绘制难 ...
- duilib 增加gif控件(基于gdi+,可控制播放暂停,自动设置大小)
转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42502081 因为项目需要我需要给duilib增加一个gif控件,目前已 ...
- HslControls组件库 工业控件库 曲线控件 时间控件 管道控件 温度计控件 阀门控件 传送带控件 进度条控件 电池控件 数码管控件等等
本篇博客主要对 HslControls 组件做一个大概的总览介绍,更详细的内容可以参照页面里的子链接,还有github上的源代码,然后进行相关的学习,和使用. Prepare 先从nuget下载到组件 ...
- WPF开源界面库及控件
WPF开源项目 WPF有很多优秀的开源项目,我以为大家都知道,结果,问了很多人,其实他们不知道.唉,太可惜了! 先介绍两个比较牛逼的界面库 1.MaterialDesignInXamlToolkit ...
随机推荐
- PKUSC 模拟赛 day2 上午总结
今天上午考得不是很好,主要还是自己太弱QAQ 开场第一题给的图和题意不符,搞了半天才知道原来是走日字形的 然后BFS即可 #include<cstdio> #include<cstr ...
- 【Linux高频命令专题(18)】tail
概述 tail 命令从指定点开始将文件写到标准输出.使用tail命令的-f选项可以方便的查阅正在改变的日志文件,tail -f filename会把filename里最尾部的内容显示在屏幕上,并且不但 ...
- AspectJ 出现错误::0 can't find referenced pointcut 的解决之道
使用AspectJ注解开发AOP应用时,会遇到以下问题: ::0 can't find referenced pointcut 这个问题,与你所在的开发环境有关,如下表 jdk version spr ...
- 34. Search for a Range
题目: Given a sorted array of integers, find the starting and ending position of a given target value. ...
- C++:概述
1.基本的输入输出,使用cin>>输入输入.使用cout<<输出 #include<iostream> using namespace std; int main( ...
- Tomcat的SessionID引起的Session Fixation和Session Hijacking问题
上一篇说到<Spring MVC防御CSRF.XSS和SQL注入攻击>,今天说说SessionID带来的漏洞攻击问题.首先,什么是Session Fixation攻击和Session Hi ...
- javascript中===与==
== equality 等同,=== identity 恒等. ==, 两边值类型不同的时候,要先进行类型转换,再比较. ===,不做类型转换,类型不同的一定不等. 类型转换规则:Boolean> ...
- Java连接oracle数据库的OCI和THIN
使用jdbc连接上oracle有两种方法: 1. 使用thin连接 由于thin驱动都是纯Java代码,并且使用TCP/IP技术通过java的Socket连接上Oracle数据库,所以thin驱动是与 ...
- BZOJ 2326 数学作业(矩阵)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2326 题意:定义Concatenate(1,N)=1234567……n.比如Concat ...
- C# MySQL 数据库操作类
using System; using System.Configuration; using System.Collections; using System.Data; using MySql.D ...