1

We have a TListView with ShowHint enabled. In the OnInfoTip handler, a hint message is constructed that is specific to the item over which the mouse is hovering. The message may include newline (#13#10) characters.

An override has been created to process CM_HINTSHOW messages and the hint message about to be displayed can be seen in msg.HintInfo.HintStr. It may be possible to calculate the size at runtime but this seems risky because the implementation details may be complex or platform-dependent.

Can the THintInfo be queried for its' bounding rectangle or is there another way to determine exactly how big the popup hint message will be when it is displayed?

This is required so an exact position of the hint (msg.HintInfo.HintPos) can be set.

AlainD
  • 5,413
  • 6
  • 45
  • 99
  • 1
    Possible duplicate of [Setting size of hint window (THintWindow) in Delphi/Lazarus](https://stackoverflow.com/questions/11472874/setting-size-of-hint-window-thintwindow-in-delphi-lazarus) – Tom Brunberg Dec 19 '17 at 13:31
  • Yes, the questions are related, good spot! While I wouldn't object to this question being closed, they come at the problem from slightly different angles. I prefer the answer given here which is more closely related to this specific question. – AlainD Dec 19 '17 at 14:43
  • But the framework should take care of that for you. You need to set the `HintPos` in the `CM_HINTSHOW` message handler. Or maybe I missed something... – kobik Dec 19 '17 at 15:47
  • @kobik: I do set the `HintPos` as you suggest, but since the message text is dynamic, I cannot know the exact position to use. If its in the top-left corner of the client area of the `TListView` then `HintPos := Self.ClientToScreen(Point(1, 1));` will suffice...but if you want the bottom-right, say, then you need to know the dimensions of the popup box to calculate the correct offset from the edge of the parent `TListView` control. – AlainD Dec 19 '17 at 21:51

1 Answers1

5

THintWindow has the function CalcHintRect that can be used for this case. The VCL will use this function when showing a HintWindow:

  with HintInfo do
    HintWinRect := FHintWindow.CalcHintRect(HintMaxWidth, HintStr, HintData);

As FHintWindow is inaccessible outside of TApplication a temporary instance would need to be created.

procedure TMyListView.CMHintShow(var Message: TCMHintShow);
var
  AHintWindow: THintWindow;
  AHintWinRect: TRect;
  ...
begin
  AHintWindow := Message.HintInfo.HintWindowClass.Create(nil);
  try
    AHintWinRect := AHintWindow.CalcHintRect(...);
    ...
  finally
    AHintWindow.Free;
  end;
end;

How correct this is depends on the THintWindowClass's implementation. But the HintWindow would show incorrectly if one could not rely on it.

A potential pitfall could be in middle-eastern locale when BidiMode is right-to-left. Then following is done additionally:

  if FHintWindow.UseRightToLeftAlignment then
    with HintWinRect do
    begin
      Delta := MultiLineWidth(HintInfo.HintStr) + 5;
      Dec(Left, Delta);
      Dec(Right, Delta);
    end;
nil
  • 1,320
  • 1
  • 10
  • 21
  • I created a `THintWindow` on-the-fly and called `myHintWnd.CalcHintRect(...)`. Works nicely. – AlainD Dec 19 '17 at 14:45
  • Oh, good point. I did not realize that there is no property to access `FHintWindow`, so temp creation is definitely needed. – nil Dec 19 '17 at 14:58
  • 1
    @AlainD, I don't know what problem you are trying to solve, but I think you are doing it wrong IMO. You create a `THintWindow` just so you can get the *dimensions* of the hint window? If you *must* take the implementation from `THintWindow.CalcHintRect` where it simply uses `DrawText` with `DT_CALCRECT`. But again, My feeling is that you are on the wrong path here. – kobik Dec 19 '17 at 15:45
  • @kobik: I have a touchscreen application (mouse cursor is hidden) and the popup hint box can sometimes "get in the way" of the selected item in the list. I'm trying to tuck the popup message into one of the corners of the parent `TListView` so that the data is displayed, but without obscuring the selected item nor the item above and below. nil's answer does the trick, though you may be right that its not the most elegant. – AlainD Dec 20 '17 at 15:58