您的位置:首页 > 其它

修改鼠标光标的形状(一)

2007-05-07 21:19 363 查看
我还是比较习惯通过案例说明问题,需求案例描述如下:实现一个从 CDialog 派生的窗口类,要求当鼠标移动到窗口客户区的时候,修改鼠标指针的形状,使其显示一个小手的形状。

为了后面阐述方便,我们假设该派生窗口类名称为 CMyDialog,鼠标光标对应资源为 IDC_CURSOR_HAND。

经常看到有的同僚会用下面这种不太好的方法来实现上面的需求:
(1)在 CMyDialog 中添加 WM_MOUSEMOVE 消息的映射函数 void CMyDialog::OnMouseMove();
(2)在 OnMouseMove() 中通过调用 SetCursor() 来改变光标形状,代码如下:

void CMyDialog::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
SetCursor(::LoadCursor(AfxGetResourceHandle(), MAKEINTRESOURCE(IDC_CURSOR_HAND)));
CDialog::OnMouseMove(nFlags, point);
}

这种实现方法主要存在两个缺陷:首先是闪烁问题,眼尖的人应该能看出在鼠标移动过程中,光标会有较明显的闪烁现象;其次是在鼠标点击,双击的时候,SetCursor() 的行为失效,光标形状会变回默认的指针形状。

其实在 MFC 程序中,要修改鼠标光标形状有下面三种比较正统的方法可以用,所谓正统不是我吹的,它们出自 MSDN 技术文章:《HOWTO: Change the Mouse Pointer for a Window in MFC (Q131991)》。

Three Methods
Here are three ways an application can change the mouse pointer in a window:
(1)Override the CWnd::OnSetCursor() function. Call Windows API SetCursor() function to change the pointer.
(2)Register your own window class with the desired mouse pointer, override the CWnd::PreCreateWindow() function, and use the newly-registered window class to create the window.
(3)To show the standard hourglass pointer, an application can call the CCmdTarget::BeginWaitCursor(), which displays the hourglass, and call CmdTarget::EndWaitCursor() to revert back to the default pointer. This scheme works only for the duration of a single message. If the mouse is moved before a call to EndWaitCursor is made, Windows sends a WM_SETCURSOR message to the window underneath the pointer. The default handling of this message resets the pointer to the default type, the one registered with the class, so you need to override CWnd::OnSetCursor() for that window, and reset the pointer back to the hourglass.

方法一和方法二主要针对于那些与需求案例类似的,希望在程序中定制鼠标光标形状的需求。这两种方法都可以实现把系统默认的鼠标光标(以下简称默认光标)形状修改为定制的光标形状。方法三主要是针对沙漏形状的鼠标光标(以下简称沙漏光标)的应用,沙漏光标是 Windows 操作系统里面一项比较重要和常见的用户体验,对于那些执行周期相对比较长的(通常是需要用户稍微等待一段时间的)操作,系统往往会在操作执行的过程中把默认光标修改为沙漏光标,以提示用户需要等待。

在后面的文章中,我将在 MSDN 技术文章的基础上,结合我自己的实践,通过实际可运行的代码来解释上面这三种方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: