将鼠标光标更改为等待光标,然后启动工作线程并在线程完成时改回

changing mouse cursor to wait cursor then starting worker thread and changing back on thread completion

在较旧的 MFC 应用程序中,我必须向另一台计算机执行网络连接请求,如果计算机名称不正确,请求超时可能需要几秒钟。所以我启动了一个工作线程来建立初始连接,以便用户界面仍然可以响应。

网络连接请求由用户选择一个菜单项触发,该菜单项弹出一个对话框以填写目标计算机信息。当用户单击对话框上的确定按钮时,将使用工作线程处理网络连接请求。

我想做的是将鼠标光标更改为等待指示器,然后在实际建立连接或尝试超时后删除等待指示器。

我 运行 的是鼠标光标仍然是一个指针,鼠标光标没有变成等待指示器。

我最初的想法是,我可以使用 BeginWaitCursor() 函数更改鼠标光标。但是,这没有任何效果,我可以看到。

进一步阅读表明我还需要覆盖 CScrollView class 的 afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 方法但是我似乎找不到任何有用的描述我的东西需要用那个方法做。 OnSetCursor() 方法似乎由于各种原因被调用,只需移动鼠标就会触发该方法中的断点。

看起来在 OnSetCursor() 方法中我应该检测当前的应用程序状态,并基于此使用 SetCursor() 函数设置先前加载的可能的鼠标光标样式之一LoadCursor()。参见 as well as Change cursor for the duration of a thread

但是我不确定这是否是实际完成的方式以及 OnSetCursor() 提供的参数的实际含义以及如何使用它们。

在上面两个 SO 帖子的第二个中,似乎使用了一个全局变量来决定是否调用默认 CView::OnSetCursor() 方法。

首先声明如下全局变量:

BOOL bConnecting = FALSE; // TRUE if connecting, set by your application
HCURSOR hOldCursor = NULL; // Cursor backup

当需要显示沙漏光标时调用:

bConnecting = TRUE;
hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

连接建立(或失败)后调用:

bConnecting = FALSE;
SetCursor(hOldCursor);
// Alternatively you can call SetCursor(LoadCursor(NULL, IDC_ARROW)); - no need to backup the cursor then
// Or even not restore the cursor at all, it will be reset on the first WM_MOUSEMOVE message (after bConnecting is set to FALSE)

您还需要覆盖 OnSetCursor():

BOOL CMainFrame::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    if (bConnecting) return TRUE; // Prevent MFC changing the cursor

    // else call the default
    return CFrameWndEx::OnSetCursor(pWnd, nHitTest, message);
}

并将 ON_WM_SETCURSOR() 指令添加到 CMainFrame 的消息映射以启用 OnSetCursor() 消息处理程序。

"main-frame" 是 MFC 应用程序中所有 windows 的父级,这就是我们为它覆盖 OnSetCursor() 的原因。它会影响所有其他 windows.

在 MFC 环境中,您还可以使用 BeginWaitCursor()RestoreWaitCursor()EndWaitCursor() 函数。这些是 CCmdTarget 方法,可以使用 AfxGetApp() 以及任何 CWnd 派生的 class.

访问

请注意,在同时具有 UI 线程和工作线程的多线程环境中使用全局变量,取决于线程如何使用和访问全局变量,您可能会产生竞争条件。

@Constantine 的 OnSetCursor 实现对我不起作用(VC++ 2013;Win 10)- 启动线程后等待光标仍然返回箭头。但是我用下面的代码解决了我的问题。

BOOL CMainFrame::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    if (bConnecting) {
          SetCursor(LoadCursor(NULL, IDC_WAIT));
          return TRUE; // Prevent MFC changing the cursor
    }
    // else call the default
    return CFrameWndEx::OnSetCursor(pWnd, nHitTest, message);
}

请注意,如果您想在悬停在视图上时显示等待光标,则所有打开的对话框或视图都应具有 OnSetCursor。