#include "stdafx.h" //如果编译错误指向这里,请删除这一行 #include "MouseSrcoll.h" /**************************************************************************** CMouseScroll实现鼠标中键在客户区拖动时,滚动条随之滚动的方法 说明: 1,窗口的滚动条必须是窗口自带的。若过是手动添加的滚动条,需要修改以下代码。 2. 此类实现的根本原理是向窗口发送WM_VSCROLL或WM_HSCROLL消息,但有时窗口并不会响应我们 发送的消息。情况如下: (1)Edit控件可以响应SB_THUMBTRACK消息,即平时鼠标按下滚动条拖动时的消息。 ::SendMessage(hWnd,WM_VSCROLL,MAKEWPARAM(SB_THUMBTRACK,VScrollBarNewPos),0); (2)像List Box 和 List Control等列表控件不能响应SB_THUMBTRACK消息, 所以我们只能对窗口发送SB_LINEDOWN或SB_LINEUP消息 ::SendMessage(hWnd,WM_VSCROLL,MAKEWPARAM(SB_LINEDOWN,VScrollBarNewPos),0); (3)我们首先对窗口发送SB_THUMBTRACK消息,之后调用::GetScrollPos(hWnd,SB_VERT) 获取滚动条的位置,判断它的位置是否改变了,如果改变,则说明窗口响应了SB_THUMBTRACK消息 如果没有改变,我们需要再发送SB_LINEDOWN或SB_LINEUP消息。 (4)当发送SB_LINEDOWN或SB_LINEUP消息时,我们用while循环,不停发送,直到滚动条的位置是 我们希望调整到的位置 3. 你可以通过设置成员函数中MouseDown(HWND hWnd,POINT point,int flag)中flag的值来 达到不同的操作方式。flag可以为以下的几种组合 MOUSE_RESETPOS //鼠标重新定位标志 MOUSE_VSCROLL //可控制垂直滚动条 MOUSE_HSCROLL //可控制水平滚动条 一、使用方法: (1)鼠标按下时,调用如下: void CMyListCtrl::OnMButtonDown(UINT nFlags, CPoint point) { CMouseScroll::MouseDown(m_hWnd,point,MOUSE_VSCROLL|MOUSE_HSCROLL); return; CListCtrl::OnMButtonDown(nFlags, point); } (2)鼠标按下并且移动时: void CMyListCtrl::OnMouseMove(UINT nFlags, CPoint point) { if (nFlags&MK_MBUTTON) CMouseScroll::MouseMoving(m_hWnd,point); CListCtrl::OnMouseMove(nFlags, point); } (3)鼠标弹起时: void CMyListCtrl::OnMButtonUp(UINT nFlags, CPoint point) { CMouseScroll::MouseUp(point); //返回值为true表示鼠标移动了,返回false没有移动 return; CListCtrl::OnMButtonUp(nFlags, point); } 三、鼠标位置和滚动条位置对应原理: 鼠标移动的距离 滑块移动的距离 (滚动条窗口的范围要排除2个按钮供34个像素) ------------------- = ---------------------- 滚动条窗口的范围 滚动条的范围 即: 1.滑块移动的距离=鼠标移动的距离*滚动条的范围/滚动条窗口的范围 2.鼠标移动的距离=滑块移动的距离*滚动条窗口的范围/滚动条的范围 四、希望对你有所帮助,谢谢!阿弥陀佛! Jacky qiujiejia@gmail.com 2010-11-11 ****************************************************************************/ //滚动条上下箭头的高度 #define SCROLLBAR_BUTTON_HEIGHT 17 int CMouseScroll::VMouseBeginPos=0; //鼠标的垂直起始位置 int CMouseScroll::VScrolWndRange=0; //垂直滚动条窗口的范围 int CMouseScroll::VScrollBarRange=0; //垂直滚动条的范围 int CMouseScroll::VScrollBarBeginPos=0; //垂直滑块的起始位置 int CMouseScroll::VScrollBarMaxPos=0; //垂直滑块的最大位置 int CMouseScroll::HMouseBeginPos=0; //鼠标的水平起始位置 int CMouseScroll::HScrolWndRange=0; //水平滚动条窗口的范围 int CMouseScroll::HScrollBarRange=0; //水平滚动条的范围 int CMouseScroll::HScrollBarBeginPos=0; //水平滑块的起始位置 int CMouseScroll::HScrollBarMaxPos=0; //水平滑块的最大位置 int CMouseScroll::flag=0; POINT CMouseScroll::LastMousePos; bool CMouseScroll::MouseUp(POINT point) { ReleaseCapture(); flag=0; return (LastMousePos.x==point.x && LastMousePos.y==point.y) ? true :false; //鼠标有无移动 } void CMouseScroll::MouseDown(HWND hWnd,POINT point,int Moveflag) { CMouseScroll::flag=Moveflag; //━━━━━━━━━━━━━━━━━━━━━━━━调试时提醒设置flag用到的━━━━━━━━━━ #ifdef _DEBUG if ( (flag&MOUSE_HSCROLL)==0 && (flag&MOUSE_VSCROLL)==0 ) { ::MessageBox(hWnd,TEXT("CMouseScroll::flag至少设置为MOUSE_HSCROLL和MOUSE_VSCROLL中的一个"),NULL,MB_OK); flag=0; return; } #endif //━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ::SetCapture(hWnd); ::SetCursor(::LoadCursor(NULL,IDC_SIZEALL)); //设置光标 RECT rect; ::GetWindowRect(hWnd,&rect); SCROLLINFO si={0}; si.cbSize = sizeof(si); si.fMask = SIF_RANGE|SIF_POS|SIF_PAGE; //━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━垂直滚动 if (flag&MOUSE_VSCROLL) { if (GetWindowLong(hWnd,GWL_STYLE) & WS_VSCROLL) { //获得垂直滚动条的信息 ::GetScrollInfo(hWnd,SB_VERT,&si); VScrollBarRange=si.nMax; VScrollBarBeginPos=si.nPos; VScrollBarMaxPos=si.nMax-si.nPage+1; if (VScrollBarRange!=0) //排除VScrollBarRange出项在除数里面而导致计算出错的情况 { //垂直滚动条窗口的范围 VScrolWndRange=(rect.bottom-rect.top)-SCROLLBAR_BUTTON_HEIGHT*2; if (flag&MOUSE_RESETPOS) { //计算鼠标的垂直位置 VMouseBeginPos=VScrollBarBeginPos*VScrolWndRange/VScrollBarRange+SCROLLBAR_BUTTON_HEIGHT; point.y=VMouseBeginPos; //等一下调用SetCursorPos需要用到point.y } else VMouseBeginPos=point.y; //保存鼠标的垂直位置 } else flag&=~MOUSE_VSCROLL; } else flag&=~MOUSE_VSCROLL; } //━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━水平滚动 if (flag&MOUSE_HSCROLL) { if (GetWindowLong(hWnd,GWL_STYLE) & WS_HSCROLL) { //获得水平滚动条的信息 ::GetScrollInfo(hWnd,SB_HORZ,&si); HScrollBarRange=si.nMax; HScrollBarBeginPos=si.nPos; HScrollBarMaxPos=si.nMax-si.nPage+1; if (HScrollBarRange!=0) //排除HScrollBarRange出项在除数里面而导致计算出错的情况 { //水平滚动条窗口的范围 HScrolWndRange=(rect.right-rect.left)-SCROLLBAR_BUTTON_HEIGHT*2; if (flag&MOUSE_RESETPOS) { //计算鼠标的水平位置 HMouseBeginPos=HScrollBarBeginPos*HScrolWndRange/HScrollBarRange+SCROLLBAR_BUTTON_HEIGHT; point.x=HMouseBeginPos; //等一下调用SetCursorPos需要用到point.x } else HMouseBeginPos=point.x; //保存鼠标的水平位置 } else flag&=~MOUSE_HSCROLL; } else flag&=~MOUSE_HSCROLL; } //━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━重定位鼠标位置 if (flag&MOUSE_RESETPOS) { LastMousePos.x=rect.left+point.x; LastMousePos.y=rect.top+point.y; SetCursorPos(LastMousePos.x,LastMousePos.y); ::ScreenToClient(hWnd,&LastMousePos); } else LastMousePos=point; } void CMouseScroll::MouseMoving(HWND hWnd,POINT point) { if (flag==0) return; //鼠标的位置变化了(point.y-VMouseBeginPos),则滑块相应的要变化: //(point.y-VMouseBeginPos)*VScrollBarRange/VScrolWndRange; //鼠标中建按下时调用SetCursorPos会产生一个WM_MOUSEMOVE消息, //我们这里要过滤掉这个不需要的消息,直接返回 if (LastMousePos.x==point.x && LastMousePos.y==point.y) //鼠标没有移动 return; //━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━垂直滚动 while (flag&MOUSE_VSCROLL) { if (point.y==LastMousePos.y) break; //计算滑块的垂直位置 int VScrollBarNewPos=VScrollBarBeginPos+(point.y-VMouseBeginPos)*VScrollBarRange/VScrolWndRange; //━━━━━━━━━━━━要移动的位置VScrollBarNewPos超出范围━━━━ if (VScrollBarNewPos<0) { if (::GetScrollPos(hWnd,SB_VERT)!=0 ) VScrollBarNewPos=0; else break; } else if (VScrollBarNewPos>VScrollBarMaxPos) { if (::GetScrollPos(hWnd,SB_VERT)!=VScrollBarMaxPos ) VScrollBarNewPos=VScrollBarMaxPos; else break; } //━━━━━━━━━━━━要移动的位置VScrollBarNewPos超出范围━━━━ //发送SB_THUMBTRACK消息 ::SendMessage(hWnd,WM_VSCROLL,MAKEWPARAM(SB_THUMBTRACK,VScrollBarNewPos),0); //如果位置没有发生改变,则说明滚动条不响应SB_THUMBTRACK消息,接下来发送SB_LINEDOWN消息 if (VScrollBarNewPos != ::GetScrollPos(hWnd,SB_VERT)) { //向下移动鼠标 if (point.y>LastMousePos.y) { while ( VScrollBarNewPos> ::GetScrollPos(hWnd,SB_VERT) ) ::SendMessage(hWnd,WM_VSCROLL,MAKEWPARAM(SB_LINEDOWN,0),0); } //向上移动鼠标 //最开头已经过滤了point.y==LastMousePos.y的情况,所以这里 //只可能剩下point.y<LastMousePos.y的情况了 else { while ( VScrollBarNewPos < ::GetScrollPos(hWnd,SB_VERT) ) ::SendMessage(hWnd,WM_VSCROLL,MAKEWPARAM(SB_LINEUP,0),0); } } break; } //━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━垂直滚动 while (flag&MOUSE_HSCROLL) { if (point.x==LastMousePos.x) break; //计算滑块的垂直位置 int HScrollBarNewPos=HScrollBarBeginPos+(point.x-HMouseBeginPos)*HScrollBarRange/HScrolWndRange; //━━━━━━━━━━━━要移动的位置HScrollBarNewPos超出范围━━━━ if (HScrollBarNewPos<0) { if (::GetScrollPos(hWnd,SB_HORZ)!=0 ) HScrollBarNewPos=0; else break; } else if (HScrollBarNewPos>HScrollBarMaxPos) { if (::GetScrollPos(hWnd,SB_HORZ)!=HScrollBarMaxPos ) HScrollBarNewPos=HScrollBarMaxPos; else break; } //━━━━━━━━━━━━要移动的位置HScrollBarNewPos超出范围━━━━ //发送SB_THUMBTRACK消息 ::SendMessage(hWnd,WM_HSCROLL,MAKEWPARAM(SB_THUMBTRACK,HScrollBarNewPos),0); //如果位置没有发生改变,则说明滚动条不响应SB_THUMBTRACK消息,接下来发送SB_LINEDOWN消息 if (HScrollBarNewPos != ::GetScrollPos(hWnd,SB_HORZ)) { //向下移动鼠标 if (point.x>LastMousePos.x) { while ( HScrollBarNewPos> ::GetScrollPos(hWnd,SB_HORZ) ) ::SendMessage(hWnd,WM_HSCROLL,MAKEWPARAM(SB_LINEDOWN,0),0); } //向上移动鼠标 //最开头已经过滤了point.x==LastMousePos.x的情况,所以这里 //只可能剩下point.x<LastMousePos.x的情况了 else { while ( HScrollBarNewPos < ::GetScrollPos(hWnd,SB_HORZ) ) ::SendMessage(hWnd,WM_HSCROLL,MAKEWPARAM(SB_LINEUP,0),0); } } break; } //保存LastMousePos LastMousePos=point; } |