VC++ 解决在鼠标移动时,光标闪烁的问题。其实本质是 ON_SETCURSOR的用法
在调用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) / ;
- . LPTSTR ppsz[] = { _T("Red"), _T("Green"), _T("Blue") };
- . int index;
- . if (ptCursor.x - rect.left < dx)
- . index = ;
- . else if (ptCursor.x - rect.left < * dx)
- . index = ;
- . else index = ;
- . WTL::CString str;
- . str.Format(_T("Cursor on %s part"), ppsz[index]);
- . CClientDC dc(m_hWnd);
- . dc.DrawText(str, -, &rectText, DT_CENTER | DT_VCENTER);
- . }
- . else ::SetCursor(CCursor().LoadSysCursor(IDC_ARROW));
- . return ;
- .}
闪烁产生的原因在于每次进入OnMouseMove之前,系统都会先将光标恢复成Arrow,进入OnMouseMove之后,如果光标处在RGB条带范围内则立即被设置成Cross。
解决办法就是将上面的判断逻辑放在WM_SETCURSOR的消息处理中,当然获得光标客户坐标的方式不同,代码如下所示:
- [cpp] view plaincopyprint?
- .LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
- .{
- . POINT point;
- . ::GetCursorPos(&point);
- . ScreenToClient(&point);
- . set_cursor(point);
- . return ;
- .}
- LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
- {
- POINT point;
- ::GetCursorPos(&point);
- ScreenToClient(&point);
- set_cursor(point);
- return 0;
- }
而代码中的set_cursor私有方法其实就是上面的判断逻辑,即:
- [cpp] view plaincopyprint?
- .// 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) / ;
- . LPTSTR ppsz[] = { _T("Red"), _T("Green"), _T("Blue") };
- . int index;
- . if (ptCursor.x - rect.left < dx)
- . index = ;
- . else if (ptCursor.x - rect.left < * dx)
- . index = ;
- . else index = ;
- . WTL::CString str;
- . str.Format(_T("Cursor on %s part"), ppsz[index]);
- . CClientDC dc(m_hWnd);
- . dc.DrawText(str, -, &rectText, DT_CENTER | DT_VCENTER);
- . }
- . else ::SetCursor(CCursor().LoadSysCursor(IDC_ARROW));
- .}
- // 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));
- }
这样就解决了光标闪烁的问题。
在调用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;
- }
- 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;
- }
- 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));
- }
- // 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));
- }
这样就解决了光标闪烁的问题。
VC++ 解决在鼠标移动时,光标闪烁的问题。其实本质是 ON_SETCURSOR的用法的更多相关文章
- VC++大数据量绘图时无闪烁刷屏技术实现(我的理解是,在内存上作画,然后手动显示,而不再直接需要经过WM_PAINT来处理了)
http://hantayi.blog.51cto.com/1100843/383578 引言 当我们需要在用户区显示一些图形时,先把图形在客户区画上,虽然已经画好但此时我们还无法看到,还要通过 程序 ...
- 【ios bug解决】 输入框聚焦时光标不显示
解决办法:重写user-select样式 css: user-select: text;-webkit-user-select:text;
- C#中的WinForm问题——使用滚动条时页面闪烁及重影问题
当使用鼠标进行滚动查看页面时,由于页面会频繁刷新,如果页面中控件较多会导致页面出现闪烁.重影等问题,如下图所示: 在网上搜索过该问题,大部分都说使用双缓冲可以解决此类问题,即通过设置DoubleBuf ...
- VC/MFC 当鼠标移到控件上时显示提示信息
VC/MFC 当鼠标移到控件上时显示提示信息 ToolTip是Win32中一个通用控件,MFC中为其生成了一个类CToolTipCtrl,总的说来其使用方法是较简单的,下面讲一下它的一般用法和高级用法 ...
- 通过特殊处理 Resize 事件解决 WinForm 加载时闪烁问题的一个方法
WinForm 上放置的控件多了或者有大背景图,窗体加载时就会闪烁,对于一般的闪烁,设置 DoubleBuffer=True或许有一点改善,要立竿见影的解决可以重载 CreateParams 使用 W ...
- ListView用法及加载数据时的闪烁问题和加载数据过慢问题
ListView介绍及添加数据时的闪烁问题 1. ListView类 1.1 ListView常用的基本属性: (1)FullRowSelect:设置是否行选择模式.(默认为false) 提示 ...
- 使用mx:Repeater在删除和添加item时列表闪烁
使用mx:Repeater在删除和添加item时列表闪烁 不可能在用户界面上闪闪的吧,recycleChildren属性可帮助我们 recycleChildren属性==缓存,设为true就可以了 本 ...
- 防止vuejs在解析时出现闪烁
---## 防止vuejs在解析时出现闪烁 ## 原因: 在使用vuejs.angularjs开发时,经常会遇见在如Chrome这类能够快速解析的浏览器上出现表达式({{ express }} ),或 ...
- jQuery的鼠标悬停时放大图片的效果
这是一个基于jQuery的效果,当鼠标在小图片上悬停时,会弹出一个大图,该大图会跟随鼠标的移动而移动.这个效果最初源于小敏同志的一个想法,刚开始做的时候只能实现弹出的图片是固定的,不能随鼠标移动,最后 ...
随机推荐
- Oracle 11g 密码永不过期设置
[原因/触发因素] 确定是由于oracle11g中默认在default概要文件中设置了“PASSWORD_LIFE_TIME=180天”所导致. [影响和风险] 影响 密码过期后,业务进程连接数据库异 ...
- E: Unable to correct problems, you have held broken packages 解决方法
在Ubuntu中安装软件的时候经常碰到E: Unable to correct problems, you have held broken packages.的错误,顾名思义是因为某些软件包冲突导致 ...
- 经典Linq实例语句
从技术角度而言,LINQ定义了大约40个查询操作符,如select.from.in.where以及order by(C#中).使用这些操作符可以编写查询语句.不过,这些查询还可以基于很多类型的数据,每 ...
- OAF_文件系列6_实现OAF导出XML文件javax.xml.parsers/transformer(案例)
20150803 Created By BaoXinjian
- Codeforces Round #381 (Div. 2)D. Alyona and a tree(树+二分+dfs)
D. Alyona and a tree Problem Description: Alyona has a tree with n vertices. The root of the tree is ...
- UIButton的titleLabe setAttributeSting 首次不起作用
环境xcode7.3 ios9.3 真机模拟器均出现 UIButton的titleLabe setAttributeSting 首次不起作用,之后每一次 都正常,百思不得解,无奈之下改变策略,讲but ...
- AS快捷键
Ctrl+Q 显示关键字的提示文档 Ctrl+鼠标点击 查看关键字的源码 ctrl+T 在不同的选项卡中进行切换 ctrl+J 提示当前位置输入模板 Ctrl+P 提示参数 Alt+Enter 提示 ...
- linux php bom
之前都是用cleanbom.php来去除BOM的.今天运行提示没有异常文件,但是用Fiddler还是看到了EF BB BF,删除缓存也无效,将cleanbom.php上传到生产环境也提示没有异常. 这 ...
- VC++动态链接库(DLL)编程深入浅出(zz)
VC++动态链接库(DLL)编程深入浅出(zz) 1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用 ...
- java comet
http://www.javaworld.com/article/2077995/java-concurrency/asynchronous-processing-support-in-servlet ...