Fabrizio
Fabrizio

Reputation: 8043

How to send an hint message by code?

How can I send an hint message to the application? I've tried with a little test:

  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;

Observing Memo1's lines, it seems that an empty hint message is sent everytime I set 'Hello'.

enter image description here

In a real scenario, the empty hint message will hide my hint message and I don't understand what I'm doing wrong, is this the wrong approach?

Upvotes: 0

Views: 1755

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 595827

I suspect what you are really trying to do is tweak the currently displayed hint while the mouse is moving over a control. To do that, you can use the TApplication.OnShowHint or TApplicationEvents.OnShowHint event, or subclass the target control to handle the CM_HINTSHOW message. Any of those will provide access to a THintInfo record that you can customize, eg:

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;

Note that customizing the displayed hint in this manner will not trigger the TApplication.OnHint/TApplicationEvents.OnHint event on each hint change, only when a new hint popup is displayed. OnShowHint/CM_HINTSHOW allows you to perform live updates of an existing hint popup.

hint with live updates

Upvotes: 4

David Heffernan
David Heffernan

Reputation: 612884

You are not supposed to set Application.Hint directly. The framework does so from TApplication.Idle. It does this like so:

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

Here Control is whatever control is under the mouse. Since you have not specified the Hint property for any controls in your program, whenever this code executes it sets Application.Hint to ''.

So, here is what happens:

  • You move your mouse:
  • Your mouse move handler responds to that by setting Application.Hint.
  • The message queue is emptied and TApplication.OnIdle executes.
  • This updates Application.Hint back to ''.

And then you go back to the start and repeat the back and forth.

So, yes, this really is the wrong approach. Exactly what the right approach is, I cannot really tell because I don't know your real problem. Normally you set the Hint property for components like actions, menu items, buttons, tool buttons, etc. But perhaps your needs are more dynamic. I cannot speak to them, but I believe I have explained why you observe this behaviour.

The other point that I feel is worth making is that hints are quite funny beasts. You don't ever show a hint in a synchronous fashion. You wait until the system decides that a hint is to be shown, and then provide it with the content of the hint, one way or another. And hints get shown when the application becomes idle, commonly when the mouse stops moving. Your code trying to force a hint to show in an OnMouseMove event is best described as that code working at cross-purposes to the framework.

Upvotes: 4

Related Questions