什么';在Win32中暂时切换到等待游标的正确方法是什么?(或:如何正确触发WM_SETCURSOR?)
我的问题是:什么';在Win32中暂时切换到等待游标的正确方法是什么?(或:如何正确触发WM_SETCURSOR?),c,winapi,mouse-cursor,C,Winapi,Mouse Cursor,我的问题是: 我需要将光标切换到(比如)IDC\u等待,直到我完成某些操作 SetCursor仅在鼠标移动之前有效 WM_SETCURSOR仅在鼠标移动后有效 您可能认为我可以同时执行上述两项操作,调用SetCursor并同时修改WM_SetCursor的行为,以便在将来某个时候更改光标 但我不能这么做。为什么?因为SetCursor是应用程序范围的,但是随机窗口不知道(也不应该知道)在整个应用程序中正确的光标是什么。它需要执行适当的命中测试,才能将WM_SETCURSOR发送到实际位
- 我需要将光标切换到(比如)
,直到我完成某些操作IDC\u等待
仅在鼠标移动之前有效SetCursor
仅在鼠标移动后有效WM_SETCURSOR
SetCursor
并同时修改WM_SetCursor
的行为,以便在将来某个时候更改光标
但我不能这么做。为什么?因为SetCursor
是应用程序范围的,但是随机窗口不知道(也不应该知道)在整个应用程序中正确的光标是什么。它需要执行适当的命中测试,才能将WM_SETCURSOR
发送到实际位于光标下的窗口,但不清楚正确的方法是什么
在Win32中切换光标并返回的正确方法是什么?我看到的每一个例子都很琐碎,都忽略了这些问题。1\u当它与禁用的输入相结合时,实现忙游标是最容易的。首先禁用输入
启用窗口(hwnd,FALSE)
然后设置忙碌游标SetCursor(LoadCursor(0,IDC_WAIT))代码>。现在您可以进行一些操作(理想情况下不超过5秒)。之后,启用输入启用窗口(hwnd,TRUE)代码>。当您的操作耗时超过5秒时,窗口将被“重影”,所以它将丢失标题栏上的忙碌光标和调整边框大小
2_uu如果窗口在显示忙碌光标时需要接受输入,则您不仅必须在顶层窗口的窗口过程中处理WM_usetcursor
消息,还必须处理其所有子窗口的消息(简单静态
控件除外)。这需要对这些子类进行子类化(SetWindowSubclass
),除非您可以使用一些高级框架,否则这可能是一项非常复杂的任务
在子类化窗口过程中,只需设置忙碌光标并返回TRUE
。不要为WM_SETCURSOR
案例调用DefWindowProc
或defsublassproc
switch ( message )
{
case WM_SETCURSOR:
SetCursor( MyCursor );
return TRUE;
...
}
子类化可以在每个子创建上完成,也可以稍后通过枚举它们来完成
有趣的是,它甚至适用于带有弹出列表的菜单和组合框
3_uu另一个选项是隐藏游标ShowCursor(FALSE)代码>并显示半透明窗口跟踪鼠标光标位置,并具有一些点击功能。就我个人而言,我会从显示在当前光标位置上方或下方几个像素的窗口开始
也许状态栏上的进度条或主窗口上的简单动画(沙漏?)会更容易。我想我找到了一种合理的解决方案。它并不完美(我仍然看到一些粗糙的边缘),但我认为到目前为止,它对我来说还行,而且考虑到所有的权衡,它的行为比懒惰的方法更合理
根据应用程序的复杂性,您的里程数可能会有所不同。
以下是我建议对处于类似情况的人所做的:
定义应用程序范围的消息,例如WM\u updatecorsors=WM\u app+0
通过触发WM\u SETCURSOR
,让主(GUI)线程处理WM\u updatecursors
:
a。使用GetCursorPos
和WindowFromPoint
获取光标下的线程
b。使用GetWindowThreadProcessId
检查进程和线程ID
c。如果它处于不同的过程中,请停止
d。如果它与您的进程位于不同的线程中,PostThreadMessage(thread\u id,WM\u updatecurs)
发送给它,然后停止。(这是非常不寻常的、通常很糟糕的做法;我只是为了完整起见才提到它。)
e。如果是针对您自己的线程,则使用WM\u nchitest
,如果成功,请确定(如下所述)正确的光标应该是什么(如果有的话)。如果有任何设置,请使用SetCursor
;如果没有,则发送消息(WM\U SETCURSOR)
保留对应于不同游标的计数器列表,您考虑“堆栈”。较早的元素优先级较低。不在列表中的任何内容以后都不会被覆盖或考虑
每当您想在任何线程上更改光标时,都可以根据需要自动递增或递减相应的计数器。(假定此游标位于可堆叠游标列表中。)
然后以与上述WM_updatecursors
相同的方式触发光标更新
要确定光标是否已堆叠在任何点上,请反向浏览列表,找到与第一个正计数器对应的光标。如果没有,则返回NULL
;没有堆叠的光标
在主窗口/对话框的WM_SETCURSOR
处理程序中,如前一步所述,从全局列表中计算光标,然后使用SETCURSOR
进行设置。但是,返回FALSE
,这样子窗口(如编辑控件)仍然可以在需要时覆盖它
如果我发现更多的问题,我会更新这个,但我认为总的来说,它表现得不错。应用程序范围是您想要的。使用GetCursor()、SetCursor()、挂起消息循环的慢速工具、SetCursor()进行恢复。如果慢的东西实际上没有挂起消息循环(它不清楚),那么它会变得非常困难,因为所有的子窗口都必须合作来保持沙漏。与Winform的Control.UseWaitCursor相比,它通常只在框架中实用。@HansPassant:即使我在应用程序范围内执行此操作,当我(比如)调整边框大小或将光标悬停在编辑框上时,光标仍然需要保持不受影响,否则它会被忽略