MFC案例:用鼠标移动窗口图像的实验

当使用基于对话框的MFC项目窗口显示图像时,如窗口的尺寸小于图像的尺寸,在不做缩放的情况下按照原图尺寸在窗口显示,那么只能看到图像的局部,这时我们希望可以通过鼠标移动图像进而显示其它部分。今天就进行这个实验,编译环境是VS2022。

思路:显示图像的过程就是将图像的某一部分复制到屏幕的过程。若是在鼠标左键按下、抬起及鼠标移动的消息处理函数中,通过获得图像的某一部分并发送到屏幕上,则可达到上述目的。

具体步骤如下:

一、建立一个基于对话框的MFC项目(具体步骤略)

项目名称:showPicTest,其余均按缺省设置,具体步骤略。

进入对话框界面,将自动生成的控件全部删除。

二、在桌面上放一张jpg图片,我这里使用的是:C:\Users\Administrator\Desktop\2222.jpg。

三、在showPicTestDlg.h中,以public方式声明声明一些变量,其名称及功能见下面的代码及注释:

cpp 复制代码
	CImage img; //用于载入要显示的图片文件CImage对象
	BOOL isFirst = 1; //显示标志 1--图像第一次显示 0--其它情况
	int startX, startY; //鼠标左键按下时的位置
	int imgWidth, imgHeight; //原始图像(会载入到img中)的宽、高
	int totalDisX = 0, totalDisY = 0; //鼠标多次拖动的位移值
	int DCwidth, DCheight;//客户区宽度

四、在CshowPicTestDlg::OnInitDialog()函数TODO:行下面添加一些代码,这些代码的作用是载入图片文件,获得图像的宽高;同事获得客户区的宽高,我们将以客户区的大小为标准获取图像某一部分发送给屏幕,如此图像不会被拉伸变形。具体代码如下:

cpp 复制代码
	// TODO: 在此添加额外的初始化代码
	img.Load(L"C:\\Users\\Administrator\\Desktop\\2222.jpg"); //载入图像文件
	imgWidth =img.GetWidth();// 返回当前图像的宽度(以像素为单位)
	imgHeight = img.GetHeight();// 返回当前图像的高度
	CRect DCrect; //矩形对象(用于接收对话框客户区数据)
	GetClientRect(DCrect); //获得窗口客户区坐标、宽高等数据
	DCwidth = DCrect.Width();//客户区宽度
	DCheight = DCrect.Height();//客户区高度

五、打开对话框界面,右键对话框->单击属性框中的消息按钮->选择WM_MOSEMOVE消息->单击后边add,这样在showPicTestDlg.cpp中会添加CshowPicTestDlg::OnMouseMove函数,在这个函数的TODO:行下面添加一些代码,这些代码的作用是在鼠标第一次移动时,立即将图像显示在窗口上,这些代码只执行一次。

cpp 复制代码
    if (isFirst == 1) {
		CDC* pDC; //声明设备上下文指针
	    pDC = GetDC(); //获得当前设备上下文指针(指屏幕)
	    img.Draw(pDC->m_hDC, 0, 0); //显示图片,pDC->m_hDC通过指针获得对象
	    pDC->DeleteDC(); //清理设备上下文指针
	    isFirst = 0; //仅执行一次
	} 

六、按照第五步的做法,给鼠标左键按下WB_LBUTTONDOWN消息添加处理函数CshowPicTestDlg::OnLButtonDown(),在这个函数中添加代码,目的是获得鼠标按下时的位置坐标。添加的代码具体如下:

cpp 复制代码
	startX = point.x; //鼠标左键按下时x坐标
	startY = point.y; //鼠标左键按下时y坐标

七、还是按照第五步的做法,给鼠标左键抬起WB_LBUTTONUP消息添加处理函数CshowPicTestDlg::OnLButtonUp(),接着在这个函数的TODO:行下面添加代码,这些代码的作用是通过计算历次鼠标按下后至抬起所产生的总位移(由于移动有方向所以是位移二不是距离),来判断显示图像的哪一部分。添加的代码如下:

cpp 复制代码
   //计算鼠标本次按下至抬起的x、y方向位移
	int moveDisX =  startX-point.x; 
	int moveDisY =  startY-point.y;
    //限制每次的位移量最大步超过150个像素
	if (moveDisX > 150)moveDisX = 150; 
	if (moveDisX < -150)moveDisX = -150;
	if (moveDisY > 150)moveDisY = 150;
	if (moveDisY <- 150)moveDisY = -150;
    //计算合计位移量
	totalDisX = totalDisX +moveDisX; 
	totalDisY = totalDisY + moveDisY;
	//限制合计位移量不得超出图像大小范围
	if (totalDisX > imgWidth-DCwidth)totalDisX = imgWidth-DCwidth;
	if (totalDisY > imgHeight-DCheight)totalDisY = imgHeight-DCheight;
	if (totalDisX < 0)totalDisX = 0;
	if (totalDisY < 0)totalDisY = 0;
	if (isFirst == 0) {
		CDC* pDC; //声明设备上下文指针
		pDC = GetDC(); //获得当前设备上下文指针
		img.Draw(pDC->m_hDC, 0, 0, DCwidth, DCheight, totalDisX, totalDisY, DCwidth, DCheight);
		  //pDC->m_hDC通过设备上下文指针的到设备上下文对象名
		  //参1至参5 窗口左上角坐标及窗口宽高
		  //参6至参9 欲显示的部分图像起始坐标及宽高
		pDC->DeleteDC();//清理设备上下文
	}

八、至此,实验的编程部分到此结束。试运行,无论鼠标按下后向水平、垂直、斜向运动一小段距离后抬起,显示图片都会发生相应的移动,实验目的基本上能达成。存在的问题是操作速度不能太快,快了图片可能向相反方向运动,另外移动不是连续的。

应该有更好的算法能解决这些问题,请高手朋友赐教!

附:运行效果截图

1.开始显示的图像左上角部分

2.移动后显示图像的中间部分

相关推荐
R-G-B12 小时前
【10】MFC入门到精通——MFC 创建向导对话框、属性页类、属性表类、代码
c++·mfc·创建向导对话框·创建属性页类·创建属性表类
今天又在学代码写BUG口牙20 小时前
MFC应用程序,工作线程学习记录
c++·mfc·1024程序员节
滴_咕噜咕噜3 天前
【MFC】sqlite3数据库类导入MFC项目调用
sqlite·mfc
R-G-B3 天前
【23】MFC入门到精通——MFC资源视图 报错“在另一个编辑器中打开” ,MFC Dialog窗口消失 资源视图“在另一个编译器中打开”
c++·编辑器·mfc·“在另一个编辑器中打开”·mfc dialog窗口消失
滴_咕噜咕噜4 天前
【MFC】数据库操作:数据库动态生成
数据库·c++·mfc
R-G-B4 天前
【25】MFC入门到精通——MFC静态文本框 中字符串 连续输出 不覆盖先前的文本 换行输出
c++·mfc·mfc静态文本框输出字符串·mfc静态文本框连续输出字符串·mfc静态文本框换行输出字符串
ajassi20004 天前
开源 C++ QT QML 开发(二十三)程序发布
c++·qt·mfc
R-G-B4 天前
【21】MFC入门到精通——MFC 调试及运行状态下,使用printf() 或者 cout 打印输出信息
c++·mfc·mfc调试及运行状态下打印输出·mfc 打印输出printf·mfc打印输出cout 信息
SunkingYang8 天前
详细介绍C++中捕获异常类型的方式有哪些,分别用于哪些情形,哪些异常捕获可用于通过OLE操作excel异常
c++·excel·mfc·异常捕获·comerror
R-G-B8 天前
【35】MFC入门到精通——MFC运行 不显示对话框 MFC界面不显示
c++·mfc·mfc运行 不显界面·mfc界面不显示