我们经常会看到一些平面设计软件例如AutoCAD等,在软件界面可利用鼠标进行图形的缩放功能,关键是它的缩放还根据鼠标位置的不同而实现不同的缩放功能。具体关键细节有如下情况:
1、滚轮滚动有两个方向,一般一个方向用于放大、另一个用于缩小,但具体哪个方向是放大哪个缩小,其实都无所谓,不同软件都不太一样。
2、一般鼠标停留的在哪个位置进行滚动滚轮时,给人的感觉是整个软件界面以鼠标点为中心进行缩放的,也就是图形或图像上鼠标的点不动,其余位置成比例放大缩小。不管鼠标是否落在图像内或在图像外均体现出该功能。
如果在网上搜索滚动功能的代码,经常出现很多长篇大论,有的用SDK,或底层API来写,这样显得太麻烦。又不好理解。笔者想借助VS2010开发环境,利用VC本身已有的一些功能简单地将其实现出来,这样读者易懂,代码拿去参考修改也方便。
下面我们就在MFC中开发一个滚轮根据鼠标位置缩放图形的程序:
(1)首先建立一个MFC的对话框程序,在对话框的头文件(*.h)里加入一些宏定义用于绘制矩形:
#define WIDTH 100 //矩形的宽(初始状态)
#define HEIGHT 200 //矩形的长(初始状态)
#define UP_SCALE 1.1 //放大的比例值
#define DOWN_SCALE 0.9 //缩小的比例值
#define POSITION_SCALE 0.1//位置偏移比例
以上参数可以改变,但是参数 UP_SCALE、DOWN_SCALE、POSITION_SCALE 存在一定关系, 一般情况下需满足:
UP_SCALE - 1 = 1 - DOWN_SCALE ;
POSITION_SCALE = UP_SCALE - 1 或者:POSITION_SCALE = 1 - DOWN_SCALE
(2)然后在定义一些变量,这个放在头文件或cpp文件里都可以,这里将需要绘制的矩形定义成全局变量:
CPoint startPoint; //矩形起始点坐标(左上角点)
CPoint endPoint; //矩形终点坐标 (右下角点)
CRect rc; //绘制的矩形
double scale=1.0; //矩形缩放比例,初始比例1.0
(3)在对话框源文件(*.cpp)中的OnInitDialog()函数里添加初始化代码:
tartPoint.x=10; //初始化矩形的起始点坐标(左上角点)
startPoint.y=20;
endPoint.x=startPoint.x+WIDTH;//初始化矩形的终点坐标(右下角点)
endPoint.y=startPoint.y+HEIGHT;
(4)然后在绘图函数OnPaint()函数里加入如下代码用于绘制图形:
CPaintDC dc(this); // 用于绘制的设备上下文
rc.SetRect(startPoint.x,startPoint.y,endPoint.x,endPoint.y);//设置矩形的两个角点
dc.FillRect( rc, 0 ); // 画比例改变后的矩形
dc.FillSolidRect(&rc,RGB(255,0,0));//给矩形填充颜色(红色)
(5)在类向导中添加鼠标滚轮消息WM_MOUSEWHELL的消息响应函数:OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)。说明:这里的参数zDelta代表滚轮滚动的方向,>0为正方形、<0为负方向;而pt则表示鼠标的方向,不过这里不能用pt ,因为它不是鼠标在窗口中的坐标而是鼠标在整个显示器内的坐标。在该函数内添加如下代码:
CPoint mousePoint; //定义当前鼠标的坐标点
GetCursorPos(&mousePoint); //获取当前鼠标在窗框中的坐标值
ScreenToClient(&mousePoint);
int dx = mousePoint.x-(rc.TopLeft()).x; //计算鼠标坐标点到矩形起始点X方向的向量
int dy = mousePoint.y-(rc.TopLeft()).y; //计算鼠标坐标点到矩形起始点Y方向的向量
//根据鼠标滚轮滚动方向判断缩放 与 滚动格数计算缩放比例
if(zDelta>0)
{
startPoint.x = rc.TopLeft().x-(int)(dx*POSITION_SCALE);//计算放大后的矩形起始点坐标
startPoint.y = rc.TopLeft().y-(int)(dy*POSITION_SCALE);
scale *= UP_SCALE; //计算每次放大的比例值
}
else
{
startPoint.x = rc.TopLeft().x+(int)(dx*POSITION_SCALE);//计算缩小后的矩形起始点坐标
startPoint.y = rc.TopLeft().y+(int)(dy*POSITION_SCALE);
scale *= DOWN_SCALE; //计算每次缩小的比例值
}
endPoint.x = startPoint.x+(int)(WIDTH*scale); //计算缩放后的矩形终点坐标
endPoint.y = startPoint.y+(int)(HEIGHT*scale);
Invalidate(); //重新绘制图形
return CDialogEx::OnMouseWheel(nFlags, zDelta, pt);
(6)在使用滚轮程序时如果担心窗口失去焦点,一般我们需要在WM_LBUTTONDOWN消息中的响应函数OnLButtonDown添加获取焦点功能,如下:
SetFocus();
当在窗口中点一下鼠标左键,焦点即回到窗口中,滚轮程序就有效了。