在表单上设置的光标不会显示在控件上

setted cursor on form wont show up on controls

我使用 Delphi xe-8 并使用线程进行查询,我想在我的线程工作时显示一个沙漏光标。

我将光标设置为沙漏,但是当我将鼠标悬停在窗体上的控件上时,例如在网格上,光标显示为默认;只有当我将鼠标悬停在表单本身上时,光标才会改变。我想要做的是仅在窗体和窗体上的任何控件上显示沙漏光标,而不是应用程序的其余部分。

我尝试将 Screen.Cursor 设置为 crHourGlass,但它适用于整个应用程序,因此即使我将鼠标悬停在另一个表单上,它也是一个沙漏。

可以吗?如果是我该怎么做?

当鼠标悬停在给定的 TWinControl 上时,OS 会向它发送一条 WM_SETCURSOR 消息,请求它设置屏幕光标图标。 VCL 对该消息的默认处理如下:

  1. 如果Screen.Cursor不是crDefault,就是使用的游标。

  2. 否则,如果TWinControl鼠标下方有一个TGraphicControl子节点,而它的Cursor不是crDefault,那就是光标使用过。

  3. 否则,如果TWinControl自己的Cursor不是crDefault,那就是使用的光标。

  4. 否则,消息将传递给父级 window。重复步骤 2-3。

因此,为了满足您的要求,请尝试将表单的 Cursor 设置为所需的值,并确保表单上的所有子控件的 Cursor 设置为 crDefault.

如果这不是您的选择,或者如果它不起作用,您可以让您的表单 class 覆盖它的虚拟 WndProc() 方法(或使用 message method) 直接处理 WM_SETCURSOR 消息。先调用inherited处理函数,如果消息的ResultFALSE,工作线程是运行则调用Win32的APISetCursor()函数设置您想要的光标图标,并将消息的 Result 设置为 TRUE,例如:

protected
  procedure WndProc(var Message: TMessage); override;

...

procedure TMyForm.WndProc(var Message: TMessage);
begin
  inherited;
  if (Message.Msg = WM_SETCURSOR) and (Message.Result = 0) and (Thread is Running) then
  begin
    Windows.SetCursor(Screen.Cursors[crHourGlass]);
    Message.Result := 1;
  end;
end;

private
  procedure WMSetCursor(var Message: TMessage); message WM_SETCURSOR;

...

procedure TMyForm.WMSetCursor(var Message: TMessage);
begin
  inherited;
  if (Message.Result = 0) and (Thread is Running) then
  begin
    Windows.SetCursor(Screen.Cursors[crHourGlass]);
    Message.Result := 1;
  end;
end;

这样,Screen.Cursor和个别TControl.Cursor属性仍然优先,但如果光标保持不变(即所有属性都是crDefault),那么你可以改变光标为整个Form整体,不影响其他Form。