MFC的OnMouseMove移动位置和OnMouseWheel缩放实现

1. 基本作用

OnMouseMove响应鼠标移动时间

OnMouseWheel响应鼠标中键的滚动

2. 参数说明

afx_msgvoidOnMouseMove(UINTnFlags, CPointpoint);

nFlags说明:指示虚拟按键是否按下 ,此参数可以是任何下列值的组合

MK_CONTROL 当CTRL键按下时

MK_LBUTTON 当鼠标左键按下时

MK_MBUTTON 当鼠标中键按下时(滚动不属于按下)

MK_RBUTTON 当鼠标右键按下时.

MK_SHIFT 当SHIFT按下时。

point说明:鼠标的X,Y坐标:该坐标为鼠标相对所在窗口左上角为基点的位置,是一个相对位置而不是在屏幕像素上的绝对位置。

afx_msg BOOL OnMouseWheel( UINT nFlags, shortzDelta, CPointpt );

nFlags同上

zDelta:大于0时为向上滚动,小于0时为向下滚动。A value less than zero indicates rotating back (toward the user) while a value greater than zero indicates rotating forward (away from the user). Windows下通常向上滚动缩小/窗口上移,反之放大/下移

pt::鼠标的X,Y坐标,是以其父窗口的左上角为基点的。Specifies the x- and y-coordinate of the cursor. These coordinates are always relative to the upper-left corner of the window.

3. 移动的效果实现

要实现移动,例如鼠标左键拖动butoon/图片在窗口上移动,实现的结果附加要求:鼠标放在button/图片的A点,移动之后,鼠标点依然在A点上

我们通过

a. 检测鼠标已在button/图片上(确保不是在哪都可以移动图标),并且左键按下

b. 记录鼠标当前点和上个点,计算两个的偏移值,然后使用这个偏移值来移动button/图片(MoveWindows)

(记录上个点的方法可以使用静态变量,移动完毕后,把当前点赋值给静态变量)(具体实现可以灵活处理)

实现原理是:相对静止---鼠标和对象相对位置不变,鼠标的偏移量,就是我们对象的偏移量

4. 缩放的效果实现(以鼠标点为中心缩放)

要实现缩放,例如中件滑轮向上滑动缩小,向下滑动放大button/图片,实现附加要求:鼠标放在button/图片的A点,缩放之后,鼠标点依然在A点上,缩放是以鼠标点为中心

a. 同样检测鼠标已在button/图片上(确保不是在哪都可以缩放button/图片)

b. 获取当前button/图片的高和宽(使用getClientRect)

c. 获取当前pt点x,y相对于button/图片位置,然后计算该位置相对于宽和高的比值

d. 判断zDelta正负确定放大缩小(按比例调整图片高度和宽度),并调整图片左上点(left,top)的位置,确保c中的比值不变(---确保了以鼠标所在点为中心放大或缩小)

实现原理是:相对移动---鼠标和所在对象点位置不变,鼠标所在对象点的周围 长和宽 成比例的缩放

鼠标事件

在日常用到的很多软件里,当鼠标停留在某个菜单或者按钮上一定事件,会弹出关于这个空间的一些提示信息,提示信息可以利用MFC中的CToolTipCtrl 类来实现,输出提示并不难,但是如何判断鼠标停留在某个按钮上呢?可以在对话框中响应WM_SETCOUSE消息,在响应事件中判断发生事件的窗口句柄是不是该控件句柄,如果是做出响应的操作即可,但是如果要判断光标离开控件,则相对复杂一点。因为光标离开控件后,接收鼠标移动消息的窗口句柄肯定不是该控件句柄了,也可以解决,如下:

BOOLCMy12Dlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)

{

if(pWnd->GetDlgCtrlID() == IDC_BUTTON3)

{

pWnd->SetWindowTextW(_T("Hover"));

}

else if(pWnd->GetDlgCtrlID() != IDC_BUTTON3)

{

GetDlgItem(IDC_BUTTON3)->SetWindowTextW(_T("Leave"));

}

returnCDialogEx::OnSetCursor(pWnd, nHitTest, message);

}

(注:这样做,当鼠标快速的移动的时候,就有可能出现鼠标已经离开了按钮,但按钮还是显示鼠标停留在上面的现象。)

但是如果这样的控件不止一个的时候,难道要用n个else if去判断该句柄是不是对应的控件句柄吗?这样做就有点不合理了,有没有更好的解决办法呢?

经过试验,以下方法可行且相对来说最好:

从Cbutton派生子类MyHoverBtn,在子类中响应WM_MOUSEMOVE事件,在该事件的响应函数中添加如下代码来响应鼠标的Hover和Leave事件:

void MyHoverBtn::OnMouseMove(UINT nFlags, CPointpoint)

{

TRACKMOUSEEVENT mouse_event;//定义鼠标移动事件结构体

mouse_event.cbSize = sizeof(mouse_event);//定义结构体大小

mouse_event.hwndTrack = m_hWnd;//关联窗口句柄

mouse_event.dwFlags = TME_HOVER |TME_LEAVE;//设置响应标记

mouse_event.dwHoverTime = 100/*HOVER_DEFAULT=400*/;//设置Hover的时间

_TrackMouseEvent(&mouse_event);

CButton::OnMouseMove(nFlags, point);

}

然后在子类MyHoverBtn中响应WM_MOUSEHOVER和WM_MOUSELEAVE消息,并在相应的事件响应函数中添加实现代码;例如

void MyHoverBtn::OnMouseLeave()

{

this->SetWindowTextW(_T("我离开了~"));

CButton::OnMouseLeave();

}

void MyHoverBtn::OnMouseHover(UINT nFlags, CPointpoint)

{

this->SetWindowTextW(_T("我来了~"));

CButton::OnMouseHover(nFlags, point);

}

网上有人说可以在对话框中重载PreTranslateMessage函数,判断消息类型和控件句柄,如果消息是WM_MOUSEMOVE,且该事件发生的控件句柄就是你要控制的控件句柄,则做出响应的处理,代码如下:

BOOLCMy12Dlg::PreTranslateMessage(MSG* pMsg)

{

CWnd* pWnd = GetDlgItem(IDC_BUTTON1);

if(pMsg->hwnd == pWnd->GetSafeHwnd() && pMsg->message ==WM_MOUSEMOVE)

{

CPoint point(pMsg->pt);

pWnd->ScreenToClient(&point);

CRect rect;

pWnd->GetClientRect(&rect);

if(rect.PtInRect(point))

pWnd->SetWindowTextW(_T("Hover"));

else

pWnd->SetWindowTextW(_T("Leave"));

returnTRUE;

}

returnCDialogEx::PreTranslateMessage(pMsg);

}

请注意绿色部分,这里不合理,因为当光标离开按钮控件后,鼠标移动的事件目标控件就不是该按钮了,与文章开头的方法是一样的,需要另外判断···

说了几种方式,还是派生子类,然后在子类中响应鼠标移动消息,从而做出对应操作最好。但是在设置Hover的时间的时候如果按照默认的HOVER_DEFAULT设置,也就是时间是400毫秒,那么鼠标移动到控件上面后需要等待这个时间才会响应OnMouseHover(),于是我将时间减小为100毫秒,比较合理了,如下:

mouse_event.dwHoverTime = 100/*HOVER_DEFAULT=400*/;//设置Hover的时间

就是不懂如果将时间设置到很小,会不会导致程序不断的提取鼠标移动消息,导致CPU占用增加呢?

经测试将时间设置为1毫秒,相对与设置为100毫秒,cpu也不会大幅增加,MSDN对该参数的解释如下:

dwHoverTime

Specifiesthe hover time-out (if TME_HOVER was specified in dwFlags), in milliseconds.Can be HOVER_DEFAULT, which means to use the system default hover time-out.

窗口重绘方面:

Invalidate()使窗口区域无效,以等待下一次重绘WM_PAINT消息将在消息队列为空时发送。与之类似的还有InvalidateRect(),可指定重绘具体的矩形区域。

UpdateWindow() 强制立即更新窗口,在OnPaint()函数中可以用GetUpdateRect()确定重绘区域或者判断是否需要重绘。

RedrawWindow与UpdateWindow类似,强制重绘窗口,但是它提供了更多的参数以设置重绘的区域等

在重绘时,需调用BeginPaint()来准备好用于绘画的windows设备环境,填充 PAINTSTRUCT结构,并将DC句柄返回用于重绘。

绘画结束时,需调用EndPaint()来释放设备句柄。

原文地址:https://www.cnblogs.com/mengxiaoxu/p/9212290.html

时间: 2024-10-12 15:40:19

MFC的OnMouseMove移动位置和OnMouseWheel缩放实现的相关文章

以鼠标位置为中心缩放平移图片(图片map)

最近一个项目使用一张图片实现地图类似的效果,即图片以鼠标位置为中心缩放.平移:通过度娘搜索找到几个版本,最终下面这个版本真正实现该功能:具体代码是网上Copy的,若有版权或其他问题,请联系我予以处理,有不当之处,请原作者原谅. <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>移动缩放图片</title>

在WPF里面实现以鼠标位置为中心缩放移动图片

原文:在WPF里面实现以鼠标位置为中心缩放移动图片 在以前的文章使用WPF Resource以及Transform等技术实现鼠标控制图片缩放和移动的效果里面,介绍了如何在WPF里面移动和放大缩小图片,程序也支持使用滚轮的方式缩放图片.然而前面文章里介绍的缩放功能只能以图片中心为原点来实现,但是这种功能往往并不是客户想要的,我们看图片的时候,往往都喜欢以鼠标放在图片的焦点为原点进行图片的缩放. 咋看起来,实现这个功能也不是很难, ScaleTransform类里面定义了CenterX和Center

MFC像窗体坐标位置发送 点击消息

int x11=495;                                        int y22=600;                                        LPARAM lparam111 = MAKELPARAM(x11,y22); //x坐标,y坐标                                        Sleep(100);                                        LRESUL

自定义Imageview控件实现多种手势操作 (拖动、水平缩放、竖直缩放、等比例缩放、双击、长按)

项目中需要使用自定义控件的多种手势操作,之前在网上查阅资料的时候发现能找到的一般是只实现了其中的几种,这次就把我做的控件分享一下,人人为我,我为人人嘛,哈哈! 这个自定义控件实现的主要功能是控件的拖动和缩放(注意:不是对控件中的图片进行操作,话说很多帖子都把这两个混了),其中缩放可以按照三个方向进行,就是水平.竖直和等比例.双击操作只做了一个提示,长按加上了一个简单的弹出菜单. 抱歉的是没有足够的时间写详细注释了,如果跟你需要的功能相同就请直接调用,要是需要改代码就费点神自己读懂代码吧,看不懂的

cv::namedWindow, GLFWwindow以及其他程序嵌入到MFC中的教程

cv::namedWindow, GLFWwindow以及其他程序嵌入到MFC中的教程 MFC虽然很老, 不美观, 不跨平台, 但是在Windows系统中, 利用MFC做功能验证的界面, 还是很快很方便的. 因为它老, 所以有很多解决方案可以利用, 因为它是MS提供的界面库, 所以在Windows上很容易实现, 并且和Windows系统结合很紧密. 比如说, 窗口消息等, 在MFC中是很方便实现的. 基于上面的种种原因, 利用MFC作为功能验证的一个"壳" 是很好的工具. 当然, 难免

ASP.NET 共用类库1

using System; using System.Collections.Generic; using System.Text; using System.Web; using System.Web.UI; using System.IO; using System.Drawing; using System.Drawing.Imaging; using System.Security.Cryptography; using System.Net; using System.Web.UI.W

ThinkPHP/Common/extend.php

<?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- // | Copyright (c) 2010 http://thinkphp.cn All ri

2016 SWPU CTF的WriteUp

2.1.题目信息 地址: QQ群:184517991 分值: 50分Flag: flag{welcome_swpu_ctf} 2.2.解题过程 进入他们官方的QQ群,找了一圈没找到Flag,然后问了下管理员,管理员表示Flag在历史公告,But我的Mac QQ并不能看历史公告,于是... 嗯,这是一道送分题 3.Misc150(Misc2) 2.1.题目信息 地址: http://misc.08067.me/misc2/misc.pcapng分值: 150分Flag: flag{Rgb_dhsk

我的开发助手之时间线控件

数年前因为某个原因,开始编写的我的开发助手,一路艰辛,一路坚持,目前仍不断完善之中,项目地址:https://gitee.com/sqlorm/DevelopAssistant 欢迎大家点赞和支持. 今天想和大家分享一下其中的时间线控件,这是一个通过GDI绘制和对原有事件重写来实现的用户自定义控件,界面还算美观,操作也很简捷,喜欢的同学不妨收下. 控件是这样子的: ? 没有内容时界面 ? 管理界面带编辑功能界面 下面就来介绍一下关于这个控件的开发: 第一步.我们创建一个类继承 UserContr