如何通过代码发送提示消息?

How to send an hint message by code?

如何向应用程序发送提示消息? 我试过一点测试:

  TForm1 = class(TForm)
    ApplicationEvents1: TApplicationEvents;
    Memo1: TMemo;
    procedure ApplicationEvents1Hint(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

procedure TForm1.ApplicationEvents1Hint(Sender: TObject);
begin
  Memo1.Lines.Add(Application.Hint);
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  Application.Hint := 'Hello';
end;

观察Memo1的台词,好像每次设置'Hello'.

都会发送一个空提示信息

在实际场景中,空的提示消息会隐藏我的提示消息,我不明白我做错了什么,这是错误的做法吗?

您不应该直接设置 Application.Hint。该框架从 TApplication.Idle 开始这样做。它是这样做的:

Control := DoMouseIdle;
if FShowHint and (FMouseControl = nil) then
  CancelHint;
Application.Hint := GetLongHint(GetHint(Control));

这里Control是鼠标下的任何控件。由于您没有为程序中的任何控件指定 Hint 属性,因此无论何时执行此代码,它都会将 Application.Hint 设置为 ''

所以,事情是这样的:

  • 您移动鼠标:
  • 您的鼠标移动处理程序通过设置 Application.Hint 来响应。
  • 消息队列清空,TApplication.OnIdle执行。
  • 这会将 Application.Hint 更新回 ''

然后你回到开始,来回重复。

所以,是的,这确实是错误的方法。究竟什么是正确的方法,我真的不能说,因为我不知道你真正的问题。通常,您为操作、菜单项、按钮、工具按钮等组件设置 Hint 属性。但也许您的需求更加动态。我不能和他们说话,但我相信我已经解释了为什么你会观察到这种行为。

我觉得值得提出的另一点是提示是非常有趣的野兽。您永远不会以同步方式显示提示。您等到系统决定显示提示,然后以某种方式向其提供提示的内容。当应用程序空闲时,通常会在鼠标停止移动时显示提示。您的代码试图强制在 OnMouseMove 事件中显示提示,最好将其描述为与框架交叉工作的代码。

我怀疑您真正想做的是在鼠标移到控件上时调整当前显示的提示。为此,您可以使用 TApplication.OnShowHintTApplicationEvents.OnShowHint 事件,或子类化目标控件来处理 CM_HINTSHOW 消息。其中任何一个都将提供对您可以自定义的 THintInfo 记录的访问权限,例如:

procedure TForm1.ApplicationEvents1ShowHint(var HintStr: string;
  var CanShow: Boolean; var HintInfo: THintInfo)
begin
  // HintInfo.HintControl is the control that is about to display a hint
  if HintInfo.HintControl = Memo1 then
  begin
    // HintInfo.CursorPos is the current mouse position within the HintControl
    HintStr := Format('Hello, cursor = %d,%d', [HintInfo.CursorPos.X, HintInfo.CursorPos.Y]);

    // the hint will remain active until it times out (see
    // TApplication.HintHidePause and THintInfo.HideTimeout) or
    // the mouse moves outside of the HintInfo.CursorRect.  In
    // the latter case, a new hint will be displayed. This allows
    // you to change the hint for different sections of the
    // HintControl. The CursorRect is set to the HintControl's
    // whole client area by default.

    // In this example, setting the new CursorRect to a 1x1 square
    // around the current CursorPos will display a new hint string
    // on each mouse movement...
    HintInfo.CursorRect := Rect(HintInfo.CursorPos.X, HintInfo.CursorPos.Y, HintInfo.CursorPos.X, HintInfo.CursorPos.Y);
  end;
end;

请注意,以这种方式自定义显示的提示不会在每次提示更改时触发 TApplication.OnHint/TApplicationEvents.OnHint 事件,只有在显示新的提示弹出窗口时才会触发。 OnShowHint/CM_HINTSHOW 允许您对现有提示弹出窗口执行实时更新。