2

In a Delphi 10.3.3 Windows VCL Application, in the OnHint event-handler of a TApplicationEvents component, I show the current hint in the status-bar:

procedure TForm1.ApplicationEvents1Hint(Sender: TObject);
begin
  statMain.SimpleText := Application.Hint;
end;

However, I would like to add some specific text containing specific run-time data depending on which control sends the hint.

Unfortunately, the Sender parameter does not give that information.

So how can I detect which control has sent the hint?

user1580348
  • 5,721
  • 4
  • 43
  • 105
  • Ingenious! The most simple often are the best solutions! – user1580348 Apr 10 '20 at 23:36
  • 1
    @RemyLebeau: I am aware of `OnShowHint` and its `HintInfo.HintControl`. The reason I didn't mention it is because it seems only to fire if the control has `ShowHint` set to `True` (which I never have, since I want my hints in the status bar but not as yellow popups), and it is fired with the usual popup hint delay (I want the hint immediately). The `OnHint` event doesn't have these "shortcomings". Thus, I looked for an alternative solution. I realise now that I can still suppress the hint popup with `OnShowHint`, and get rid of the delay using `Application.HintPause`. – Andreas Rejbrand Apr 11 '20 at 07:47
  • Maybe, using `OnShowHint` in addition to `OnHint` makes things unnecessarily complicated? – user1580348 Apr 11 '20 at 11:00

1 Answers1

5

The OnHint event does not provide access to any information about the control that is displaying the hint.

However, the OnShowHint event does, and you can fully customize the hint however you want in that event:

procedure TForm1.ApplicationEvents1ShowHint(var HintStr: string;
  var CanShow: boolean; var HintInfo: THintInfo);
begin
  if HintInfo.HintControl = DesiredControl then
  begin
    // customize HintStr, and/or HintInfo fields, as needed...
  end;
end;

procedure TForm1.ApplicationEvents1Hint(Sender: TObject);
begin
  statMain.SimpleText := Application.Hint;
end;

The HintInfo provides all kinds of information about the hint that you can customize:

HintControl
The name of the control for which hint processing is occurring.

HintWindowClass
The class of the hint-window control. The default is THintWindow, but you can specify any class derived from THintWindow. Use this field if you want to substitute a custom hint window for THintWindow.

HintPos
The default position in screen coordinates of the top-left corner of the hint window. Change where the window appears by changing this value.

HintMaxWidth
The maximum width of the hint window before word wrapping begins. By default, the value is the width of the screen (the Width property of the global Screen variable).

HintColor
The background color of the Hint window.

CursorRect
The rectangle the user's mouse pointer must be in for the hint window to appear. The default value for CursorRect is the client rectangle of the control. Change this value so that a single control can be divided into several hint regions. When the user moves the mouse pointer outside the rectangle, the hint window disappears.

CursorPos
The location of the mouse pointer within the control.

ReshowTimeout
How long the hint system should wait before asking about the hint status again. By default, this field is zero, indicating that the hint status will not change. Setting it to a non-zero value will cause the hint to act, after the requested milliseconds have elapsed, as if the user moved the mouse outside the hint rectangle and back in. This can be used to either put off hint processing for a period of time, or to allow the hint to be updated periodically.

HideTimeout
The number of milliseconds to show the hint. By default, it is set to the value of the Application variable's HintHidePause property.

HintStr
The string to be displayed in the hint window. This allows an OnHint event handler to modify the contents of a hint before it is displayed. By default, it contains the value returned by the GetShortHint function when passed the value of the Application variable's Hint property.

HintData
Additional data to be passed to the hint-window control. Use this field in conjunction with HintWindowClass.

Also, FYI, you don't need to use the TApplication(Event).OnHint event just to display the TApplication.Hint text in a TStatusBar. If you set the StatusBar's AutoHint property to true then the StatusBar can display TApplication.Hint updates automatically. You just need to make sure that you don't have an OnHint handler assigned, otherwise AutoHint will not work (OnShowHint is fine, though).

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • "AutoHint": I've tried that. But for some strange reason, `AutoHint` does not work in my specific situation. So, to modify the hint, I need to use your solution. – user1580348 Apr 10 '20 at 23:44
  • 1
    @user1580348 `TStatusBar.AutoHint` does not work when an `TApplication(Events).OnHint` handler is assigned. When the `TApplication.Hint` is updated, the `TApplication(Events).OnHint` event is fired if assigned, otherwise a `THintAction` is broadcasted to all controls, which is what `TStatusBar` listens for when `AutoHint` is True. So, if you want to use `AutoHint` then DON'T use `OnHint` (`OnShowHint` is fine, though). – Remy Lebeau Apr 10 '20 at 23:50
  • This is very strange: Sometimes, the `OnShowHint` event occurs AFTER the `OnHint` event! Why is this so? – user1580348 Apr 11 '20 at 00:07
  • Even more strange: if I put a `CodeSite.Send` debug message into both `OnHint` and `OnShowHint` event-handlers, then the debug message in the `OnShowHint` event-handler is not being sent, only the debug message in the `OnHint` event-handler is being sent! – user1580348 Apr 11 '20 at 00:17
  • Make sure `TApplication.ShowHint` is True (it is False by default). `OnHint` is fired *immediately* when the `TApplication.Hint` is assigned a new value, whether a hint window will be displayed or not. `OnShowHint` is fired just before a hint window is displayed/updated, which can indeed be delayed, depending on various criteria on when the VCL actually processes the request to display the hint (a mouse event, a timer, etc). `OnShowHint` is always fired just before a new hint window is displayed, or an active hint window is updated. – Remy Lebeau Apr 11 '20 at 00:39
  • With `statMain.SimpleText := Application.Hint;` in the `OnHint` event-handler, the LONGHINT is being shown in the status-bar and the SHORTHINT is being shown on the control's mouse hover. This behavior is intentional. HOWEVER, when I add a text to `HintStr` in the `OnShowHint` event-handler, then this added text is being added to the SHORTHINT (on Mouse-Hover) and NOT to the LONGHINT in the status-bar (which is my intention). So it seems I must retrieve the hint-control in the `OnShowHint` event-handler, store the control's name in a variable and then add the text for this control in OnHint. – user1580348 Apr 11 '20 at 07:12
  • @RemyLebeau: Are you sure `TApplication.ShowHint ` is `False` by default? The [documentation](http://docwiki.embarcadero.com/Libraries/Rio/en/Vcl.Forms.TApplication.ShowHint) says otherwise. – Andreas Rejbrand Apr 11 '20 at 07:53
  • 1
    @RemyLebeau: As far as I can tell, the documentation is right. It is `True` by default. Being a member of a class, the field is initially `False`, and it is also needlessly set to `False` in `TApplication.Create` (Vcl.Forms:9617 in 10.3.2). But `TApplication.Create` is called by `Vcl.Controls.InitControls` (from the unit's `initialization` section), at line `Vcl.Controls.pas:16545` in Delphi 10.3.2. The next line after `Application := TApplication.Create(nil)` is `Application.ShowHint := True`. And indeed, in the main form's `OnCreate`, for instance, `Application.ShowHint` is `True`. – Andreas Rejbrand Apr 11 '20 at 09:44
  • Unfortunately, the `OnShowHint` event seems to occur for hint-less controls too. This creates a problem which together with the other problems of `OnShowHint` makes me think to rather use `FindDragTarget` instead. – user1580348 Apr 11 '20 at 10:53