修复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

 

你可能感兴趣的:(slider)