鼠标中键按下拖动滚动条(平移视图)

来源:互联网 发布:菜鸟网络马云股份 编辑:程序博客网 时间:2024/05/25 01:36

鼠标中键按下拖动滚动条(平移视图)


 

以下代码演示了鼠标中键在客户区拖动时,滚动条随之滚动的方法。其实就是用鼠标平移视图了。

 

示例代码下载:鼠标中键按下拖动滚动条(平移视图).zip (请不要直接使用迅雷下载)

注:VC6下编译通过

 


 

 

一、为了不要吓着大家,我先把代码简化了。这简单的例子演示如何在

    文本框中按下中建拖动时,垂直滚动条随之滚动。

    我觉得原来的中键滚动视图实在不好用。

 

1.派生一个类CMyEdit,继承于CEdit。

2.然后为CMyEdit类添加3个消息函数

void CMyEdit::OnMButtonDown(UINT nFlags, CPoint point)
void CMyEdit::OnMButtonUp(UINT nFlags, CPoint point)
void CMyEdit::OnMouseMove(UINT nFlags, CPoint point)

 

3.接着在源文件中添加以下代码即可运行。

//滚动条上下箭头的高度
#define SCROLLBAR_BUTTON_HEIGHT 17

int VMouseBeginPos;  //鼠标的垂直起始位置
int VScrolWndRange;  //垂直滚动条窗口的范围
int VScrollBarRange; //垂直滚动条的范围
int VScrollBarBeginPos; //垂直滑块的起始位置

//鼠标按下时不重新定位
void CMyEdit::OnMButtonDown(UINT nFlags, CPoint point)
{
  ::SetCapture(m_hWnd);
  ::SetCursor(::LoadCursor(NULL,IDC_SIZEALL)); //设置光标
  
  RECT rect;
  ::GetWindowRect(m_hWnd,&rect);
  
  SCROLLINFO si={0};
  si.cbSize = sizeof(si);
  si.fMask = SIF_RANGE|SIF_POS;
  
  //获得垂直滚动条的信息
  ::GetScrollInfo(m_hWnd,SB_VERT,&si);
  VScrollBarRange=si.nMax;
  VScrollBarBeginPos=si.nPos;
  if (VScrollBarRange!=0)  //排除VScrollBarRange出项在除数里面而导致计算出错的情况
  {
   //垂直滚动条窗口的范围
   VScrolWndRange=(rect.bottom-rect.top)-SCROLLBAR_BUTTON_HEIGHT*2;
   VMouseBeginPos=point.y; //保存鼠标的垂直位置
  }
  
  return ; 
 CEdit::OnMButtonDown(nFlags, point);
}


void CMyEdit::OnMButtonUp(UINT nFlags, CPoint point)
{
 ReleaseCapture();
 return;
 CEdit::OnMButtonUp(nFlags, point);
}


void CMyEdit::OnMouseMove(UINT nFlags, CPoint point)
{
 if (nFlags&MK_MBUTTON)
 {
  //鼠标的位置变化了(point.y-VMouseBeginPos),则滑块相应的要变化:
  //(point.y-VMouseBeginPos)*VScrollBarRange/VScrolWndRange;
  
  //重新定位滑块的垂直位置
  int VScrollBarNewPos=VScrollBarBeginPos+(point.y-VMouseBeginPos)*VScrollBarRange/VScrolWndRange;
  if (VScrollBarNewPos<0) VScrollBarNewPos=0;
  ::SendMessage(m_hWnd,WM_VSCROLL,MAKEWPARAM(SB_THUMBTRACK,VScrollBarNewPos),0); 
  
  return; 
 }
 CEdit::OnMouseMove(nFlags, point);
}

  

4.效果不错吧!

 


 

二、下面我把它封装成一个类,方便使用。

 

代码:

MouseSrcoll.h

 

#ifndef _MOUSE_SCROLL_H_
#define _MOUSE_SCROLL_H_

#include <Windows.h>
#define MOUSE_RESETPOS  0x00000004  //鼠标重新定位标志
#define MOUSE_VSCROLL  0x00000008 //可控制垂直滚动条
#define MOUSE_HSCROLL  0x00000010 //可控制水平滚动条


class CMouseScroll
{
 static int VMouseBeginPos;  //鼠标的垂直起始位置
 static int VScrolWndRange;  //垂直滚动条窗口的范围
 static int VScrollBarRange;  //垂直滚动条的范围
 static int VScrollBarBeginPos; //垂直滑块的起始位置
 static int VScrollBarMaxPos; //垂直滑块的最大位置

 static int HMouseBeginPos;  //鼠标的水平起始位置
 static int HScrolWndRange;  //水平滚动条窗口的范围
 static int HScrollBarRange;  //水平滚动条的范围
 static int HScrollBarBeginPos; //水平滑块的起始位置
 static int HScrollBarMaxPos; //水平滑块的最大位置

 static POINT LastMousePos;
 static int  flag;

public:
 static bool MouseUp(POINT point);
 static void MouseMoving(HWND hWnd,POINT point);
 static void MouseDown(HWND hWnd,POINT point,int Moveflag);
};

 

#endif  // #define _MOUSE_SCROLL_H_

 

 

MouseSrcoll.cpp

 

#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; 
}

 

 


 

 

 

推荐:

狮姐的博客(狮子窝,学佛与灵魂之探究)
大方广(学习传统文化)
慈善点击(轻松一点,行善积德,何乐不为)
电影《地球公民》(揭示不为人知的一面)  
心向光明 远离邪淫(现世警钟,不可不看)
戒淫(上篇)(正淫节欲,戒除邪淫) 
戒淫(中篇)(纵欲之乐,忧患随之)
公民教育——命由我造

原创粉丝点击