如何停止 Screen.Cursor 影响窗体上的所有控件?

zig*_*zig 5 delphi vcl delphi-7

我会尽量简化我的问题。例如,如果您删除 2TSpeedButton并执行以下操作:

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  Screen.Cursor := crHourGlass;
  SpeedButton2.Cursor := crHandPoint; // note I'm setting other cursor than crDefault
end;
Run Code Online (Sandbox Code Playgroud)

SpeedButton2.Cursor显示Screen.Cursor设置为的剩余部分crHourGlass
我已经调查了TScreen.SetCursor代码,并意识到它为整个表单设置了光标。
我的问题:是否有可能以某种方式使用Screen.Cursor整个表单,但不会影响我想设置其他光标的某些控件。

同样的情况发生在TButton. 如果我可以在Screen.Cursor设置为时以某种方式控制它的光标,我不介意将 SpeedButton 放在窗口控件上crHourGlass

谢谢。

Ser*_*yuz 7

这是故意行为,如文档中所述TScreen.Cursor

... 当 Cursor 为 crDefault 时,单个对象确定光标图像。分配任何其他值将为属于应用程序的所有窗口设置鼠标光标图像。全局鼠标光标图像一直有效,直到屏幕的 Cursor 属性改回 crDefault。..


窗口控件在TWinControl.WMSetCursor过程、WM_SETCURSOR消息处理程序中处理它们的光标,如果屏幕光标不是crDefault它们自己的光标,则它们显式设置屏幕光标并忽略它们自己的光标。

因此,要更改行为,您可以处理提到的消息。对于TButton中介层,示例可能是:

procedure TButton.WMSetCursor(var Message: TWMSetCursor);
begin
  if (Cursor <> crDefault) and (Message.HitTest = HTCLIENT) then begin
    Message.Result := 1;
    Windows.SetCursor(Screen.Cursors[Cursor]);
  end else
    inherited;
end;
Run Code Online (Sandbox Code Playgroud)



图形控件的光标由其父级处理TWinControl。因此,要更改速度按钮的行为,您仍然需要在其父级上处理相同的消息。这可能是不切实际的,因为可能事先不知道父类。

尽管如此,一个非常非通用的实现,例如直接放置在表单上的图形控件,可能如下所示:

procedure TForm1.WMSetCursor(var Message: TWMSetCursor);
var
  SmPt: TSmallPoint;
  Control: TControl;
begin
  DWORD(SmPt) := GetMessagePos;
  Control := ControlAtPos(ScreenToClient(SmallPointToPoint(SmPt)), True);
  if Assigned(Control) and Boolean(Control.Tag) then begin
    Message.Result := 1;
    Windows.SetCursor(Screen.Cursors[Control.Cursor])
  end else
    inherited;
end;
Run Code Online (Sandbox Code Playgroud)

上面的示例要求图形控件具有非零标记值。例如:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Screen.Cursor := crHourGlass;
  SpeedButton1.Cursor := crHandPoint;
  SpeedButton1.Tag := 1;
end;
Run Code Online (Sandbox Code Playgroud)