Legionar
Legionar

Reputation: 7597

How to change hint text while hint is shown in TBalloonHint?

Before I used THint, and it was working with this code:

procedure TMainForm.FormCreate(Sender: TObject);
begin
  Application.OnShowHint := AppShowHint;
end;

procedure TMainForm.AppShowHint(var HintStr: String; var CanShow: Boolean; var HintInfo: Controls.THintInfo);
begin
  HintInfo.ReshowTimeout := 1;
end;

Now I use TBalloonHint and want to change hint text when hint is shown. The above procedure is not triggered.

I am changing the hint text each second, so when user enters control, the hint is shown and I want to update the hint text each second, also when user is not moving with the mouse.

How to achieve this with TBalloonHint?

Upvotes: 1

Views: 1840

Answers (1)

Asaq
Asaq

Reputation: 541

TBalloonHint does not support this functionality. The following code (Delphi XE3) adds it.

Cons:

  • CPU load - every call TBalloonHint.ShowHint creates a new TCustomHintWindow
  • flickering when redrawing

type
  TMyHintWindow = class(THintWindow)
  public
    function CalcHintRect(MaxWidth: Integer; const AHint: string;
      AData: TCustomData): TRect; override;
    function ShouldHideHint: Boolean; override;
  end;

var BalloonHint: TBalloonHint;
    _HintPos: TPoint;

function TMyHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: string;
  AData: TCustomData): TRect;
begin
  Result := Rect(0,0,0,0);
end;

function TMyHintWindow.ShouldHideHint: Boolean;
begin
  Result := True;
  BalloonHint.Free; BalloonHint := nil;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  HintWindowClass := TMyHintWindow;
  Application.OnShowHint := AppShowHint;
end;

procedure TMainForm.AppShowHint(var HintStr: String; var CanShow: Boolean; var HintInfo: THintInfo);
begin
  HintInfo.ReshowTimeout := 1;

  if not Assigned(BalloonHint)
  then begin
    BalloonHint := TBalloonHint.Create(Self);
    _HintPos := Point(MaxInt, MaxInt);
  end;

  if (_HintPos <> HintInfo.HintPos) or (BalloonHint.Description <> HintStr)
  then begin
    _HintPos := HintInfo.HintPos;
    BalloonHint.Description := HintStr;
    BalloonHint.ShowHint(_HintPos);
  end;
end;

Another ways:

  • rewrite TMyHintWindow.CalcHintRect and .Paint taking code from TBalloonHint

  • rewrite TMyHintWindow using Tooltip Controls

Add: Use tooltip control. Try also set HintInfo.ReshowTimeout := 25.

uses Windows, Vcl.Controls, System.Classes, Winapi.CommCtrl, Winapi.Messages;

type
  TTooltipHintWindow = class(THintWindow)
  private
    TooltipWnd: HWND;
    TooltipInfo: TToolInfo;
    TooltipText: string;
    TooltipPos: TPoint;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure ActivateHint(Rect: TRect; const AHint: string); override;
    function CalcHintRect(MaxWidth: Integer; const AHint: string; AData: TCustomData): TRect; override;
    function ShouldHideHint: Boolean; override;
  end;

implementation

procedure TTooltipHintWindow.ActivateHint(Rect: TRect; const AHint: string);
begin
  inherited;
  if (TooltipText <> AHint)
  then begin // update text
    TooltipText := AHint;
    TooltipInfo.lpszText := PChar(TooltipText);
    SendMessage(TooltipWnd, TTM_UPDATETIPTEXT, 0, LParam(@TooltipInfo));
  end;
  if (TooltipPos <> Rect.TopLeft)
  then begin // update position
    TooltipPos := Rect.TopLeft;
    SendMessage(TooltipWnd, TTM_TRACKPOSITION, 0, PointToLParam(TooltipPos));
  end;
  // show
  SendMessage(TooltipWnd, TTM_TRACKACTIVATE, WParam(True), LParam(@TooltipInfo));
end;

function TTooltipHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: string;
  AData: TCustomData): TRect;
begin
  Result := Rect(0,0,0,0);
end;

constructor TTooltipHintWindow.Create(AOwner: TComponent);
var font, boldfont: HFONT;
    logfont: TLogFont;
begin
  inherited;
  // create tooltip
  TooltipWnd := CreateWindowEx(WS_EX_TOPMOST or WS_EX_TRANSPARENT,
    TOOLTIPS_CLASS, nil,
    TTS_NOPREFIX or TTS_ALWAYSTIP or TTS_BALLOON,
    0, 0, 0, 0, 0, 0, HInstance, nil);
  // set bold font
  font := SendMessage(TooltipWnd, WM_GETFONT, 0, 0);
  if (font <> 0)
  then begin
    if GetObject(font, SizeOf(logfont), @logfont) > 0
    then begin
      logfont.lfWeight := FW_BOLD;
      boldfont := CreateFontIndirect(logfont);
      SendMessage(TooltipWnd, WM_SETFONT, boldfont, 0);
    end;
  end;
  // set maximum width
  SendMessage(TooltipWnd, TTM_SETMAXTIPWIDTH, 0 , 400);
  // init
  FillChar(TooltipInfo, SizeOf(TooltipInfo), 0);
  TooltipInfo.cbSize := SizeOf(TooltipInfo);
  TooltipInfo.uFlags := TTF_TRACK or TTF_TRANSPARENT;
  TooltipInfo.uId := 1;
  SendMessage(TooltipWnd, TTM_ADDTOOL, 0, LParam(@TooltipInfo));
end;

destructor TTooltipHintWindow.Destroy;
begin
  DestroyWindow(TooltipWnd);
  inherited;
end;

function TTooltipHintWindow.ShouldHideHint: Boolean;
begin
  inherited;
  // hide
  SendMessage(TooltipWnd, TTM_TRACKACTIVATE, WParam(False), LParam(@TooltipInfo));
  TooltipPos := Point(MaxInt, MaxInt);
  TooltipText := '';
end;

Upvotes: 3

Related Questions