鼠标中键按下拖动滚动条(平移视图)
来源:互联网 发布:菜鸟网络马云股份 编辑:程序博客网 时间: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.接着在源文件中添加以下代码即可运行。
//滚动条上下箭头的高度 int VMouseBeginPos; //鼠标的垂直起始位置 //鼠标按下时不重新定位
#define SCROLLBAR_BUTTON_HEIGHT 17
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;
}
推荐:
狮姐的博客(狮子窝,学佛与灵魂之探究)
大方广(学习传统文化)
慈善点击(轻松一点,行善积德,何乐不为)
电影《地球公民》(揭示不为人知的一面)
心向光明 远离邪淫(现世警钟,不可不看)
戒淫(上篇)(正淫节欲,戒除邪淫)
戒淫(中篇)(纵欲之乐,忧患随之)
公民教育——命由我造
- 鼠标中键按下拖动滚动条(平移视图)
- 鼠标中键拖动滚动条
- C# panel控件实现鼠标滚轮滚动拖动滚动条
- AHK不能模拟鼠标拖动滚动条的操作吗?
- AHK不能模拟鼠标拖动滚动条的操作吗?
- javascript鼠标指针拖动滚动条加载板块
- 鼠标拖动视图
- 水平滚动条拖动
- WPF ScrollViewer 滚动条鼠标移入移出及鼠标按下拖动时的外观样式
- js卷轴滚动 鼠标拖动滚动。例子
- 拖动滚动条加载数据
- 拖动滚动条时,背景图片随之滚动
- CSS学习(十八)-滚动条、拖动元素、轮廓线
- 第七章 —高级组件:拖动条seekBar、星级评分条RatingBar、进度条ProgressBar、滚动视图ScrollView
- C#鼠标滚轮处理滚动条滚动
- 隐藏滚动条、保留鼠标滚动效果
- ListCtrl控件的滚动条拖动疑难杂症
- as3拖动滚动条控制小球大小
- 关于3Q大战的感想:得民心者得天下
- 关于努力,心里等问题
- 程序虚拟地址布局
- flex LineChart 图表动态增删Y轴实现。实现了动态增加但是Y轴删不干净
- JSP中include指令和include行为的区别
- 鼠标中键按下拖动滚动条(平移视图)
- Tomcat部署web应用的几种方法
- 拯救你的字符串:微有瑕疵的终极救赎
- PDM中BOM管理技术的研究及其应用
- MFC 子对话框向父对话框传递数据
- php获取客户端ip总结
- 在SQL Server2008 上建立Oracle 链接服务器
- 学习FPGA verilog的心得--编程技巧--如何写代码减少逻辑单元的使用数量
- JSP中include指令和include行为的区别