Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么';在Win32中暂时切换到等待游标的正确方法是什么?(或:如何正确触发WM_SETCURSOR?)_C_Winapi_Mouse Cursor - Fatal编程技术网

什么';在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:即使我在应用程序范围内执行此操作,当我(比如)调整边框大小或将光标悬停在编辑框上时,光标仍然需要保持不受影响,否则它会被忽略