光标闪烁问题的解决办法

在调用Windows API函数SetCursor设置光标时,可能会碰到闪烁的问题:移动鼠标,光标在Class Cursor(即注册窗口类时指定的Cursor)与预设Cursor之间闪烁。

在MSDN上有关SetCursor函数的备注中强调,如果Class Cursor非空,那么每当鼠标移动,系统都会把光标恢复为Class Cursor。为了避免光标闪烁这一问题,必须处理WM_SETCURSOR消息。(MSDN说明)

下面是一个例子:程序在主窗口视图的中间位置绘制RGB条带,当鼠标移动在条带范围就将光标设置成为Cross,此外根据光标的位置,在RGB条带上方30px处显示所处条带的颜色。程序运行起来像这样:

如果在WM_MOUSEMOVE的消息处理中判断光标的位置并设置光标的话,就会碰到所说的光标闪烁问题。WM_MOUSEMOVE的消息处理如下代码所示:

	LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
	{
		POINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
		RECT rect, rectText;
		get_rects(&rect, &rectText);
		InvalidateRect(&rectText);
		UpdateWindow();
		if (::PtInRect(&rect, ptCursor)) {
			::SetCursor(m_cursor);
			int dx = (rect.right - rect.left) / 3;
			LPTSTR ppsz[] = { _T("Red"), _T("Green"), _T("Blue") };
			int index;
			if (ptCursor.x - rect.left < dx)
				index = 0;
			else if (ptCursor.x - rect.left < 2 * dx)
				index = 1;
			else index = 2;
			WTL::CString str;
			str.Format(_T("Cursor on %s part"), ppsz[index]);
			CClientDC dc(m_hWnd);
			dc.DrawText(str, -1, &rectText, DT_CENTER | DT_VCENTER);
		}
		else ::SetCursor(CCursor().LoadSysCursor(IDC_ARROW));
		return 0;
	}

闪烁产生的原因在于每次进入OnMouseMove之前,系统都会先将光标恢复成Arrow,进入OnMouseMove之后,如果光标处在RGB条带范围内则立即被设置成Cross。

解决办法就是将上面的判断逻辑放在WM_SETCURSOR的消息处理中,当然获得光标客户坐标的方式不同,代码如下所示:

	LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
	{
		POINT point;
		::GetCursorPos(&point);
		ScreenToClient(&point);
		set_cursor(point);
		return 0;
	}

而代码中的set_cursor私有方法其实就是上面的判断逻辑,即:

	// ptCursor: in client coordinate
	void set_cursor(POINT& ptCursor) throw()
	{
		RECT rect, rectText;
		get_rects(&rect, &rectText);
		InvalidateRect(&rectText);
		UpdateWindow();
		if (::PtInRect(&rect, ptCursor)) {
			::SetCursor(m_cursor);
			int dx = (rect.right - rect.left) / 3;
			LPTSTR ppsz[] = { _T("Red"), _T("Green"), _T("Blue") };
			int index;
			if (ptCursor.x - rect.left < dx)
				index = 0;
			else if (ptCursor.x - rect.left < 2 * dx)
				index = 1;
			else index = 2;
			WTL::CString str;
			str.Format(_T("Cursor on %s part"), ppsz[index]);
			CClientDC dc(m_hWnd);
			dc.DrawText(str, -1, &rectText, DT_CENTER | DT_VCENTER);
		}
		else ::SetCursor(CCursor().LoadSysCursor(IDC_ARROW));
	}

这样就解决了光标闪烁的问题。本例的工程文件可在这里下载,它是基于WTL的SDI程序。

P.S. 另外一个问题虽然简单但仍值得一提。上面程序的截图显示的结果实际上并不准确,Cross光标的中心已经处于Green条带,但条带上方显示的却是"Cursor on Red part"。造成此问题的原因是自定义光标的热点Hot Spot默认值为(0, 0),而不是以中心+来标识的。解决办法是在VS资源编辑器中使用Hot Spot Tool,如下图所示:

点击Cross光标的中心点,热点坐标将变成你所设置的值,如下图所示:

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
当在VMware虚拟机中开机时,可能会遇到光标闪烁问题。这个问题通常是因为显示设置不兼容或驱动程序问题引起的。如果你遇到了这个问题,可以尝试以下步骤来解决: 1. 检查分辨率:在虚拟机中,右键点击桌面背景,选择“显示设置”。确保分辨率设置与你的主机的分辨率兼容,并尝试调整分辨率以查看是否解决了光标闪烁问题。 2. 更新显卡驱动程序:在虚拟机中,右键点击桌面背景,选择“显示设置”,点击“高级显示设置”,然后选择“显示适配器属性”。在“驱动程序”选项卡中,点击“更新驱动程序”来检查是否有可用的更新驱动程序。如果有,安装最新版本的显卡驱动程序,然后重新启动虚拟机。 3. 调整硬件加速:在虚拟机中,右键点击桌面背景,选择“显示设置”,点击“高级显示设置”,然后选择“显卡”。在“硬件加速”选项中尝试切换不同的选项,然后重新启动虚拟机,看看是否解决了光标闪烁问题。 4. 检查主机和虚拟机的版本兼容性:确保你使用的VMware虚拟机版本与你的主机操作系统版本兼容。在VMware官方网站上查找系统要求和兼容性列表,以确保没有出现兼容性问题。 如果上述方法都不起作用,你可以尝试重新安装VMware工具,这会重建虚拟机的硬件设置和驱动程序。如果问题仍然存在,你可以尝试联系VMware支持团队寻求帮助,他们可能会给出更专业的解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值