2

I have this code with which I can set the font size of the control hint, but I want to be able somehow to adjust it later at runtime. How can I do that ?

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TMyHintWindow = class(THintWindow)
    constructor Create(AOwner: TComponent); override;
  end;

  TMyButton = class(TButton)
  protected
    procedure CMHintShow(var Message: TCMHintShow); message CM_HINTSHOW;
  end;

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    MyButton: TMyButton;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
 MyButton:=TMyButton.Create(Form1);
 MyButton.Parent:=Form1;
 MyButton.Caption:='Test';
 MyButton.Left:=100;
 MyButton.Top:=100;
 MyButton.ShowHint:=true;
end;

procedure TMyButton.CMHintShow(var Message: TCMHintShow);
begin
 inherited;
 Message.HintInfo.HintWindowClass:=TMyHintWindow;
 Message.HintInfo.HintStr:='My custom hint';
end;

constructor TMyHintWindow.Create(AOwner: TComponent);
begin
 inherited;
 Canvas.Font.Size:=25;
end;

end.
Marus Gradinaru
  • 2,824
  • 1
  • 26
  • 55
  • You execute `Font.Size:=SomeValue` at some later time. Presumably it should be `Font.Size` rather than `Canvas.Font.Size`. – David Heffernan Jun 22 '15 at 15:59
  • `Font.Size` of wich component ? – Marus Gradinaru Jun 22 '15 at 16:02
  • I don't understand. Can you please post a code ? – Marus Gradinaru Jun 22 '15 at 16:08
  • No. I don't know when you want to trigger a change. I guess what is tricky is that the hint window instance is not created by you and it's hard for you to find it. You are probably right to use `Canvas.Font` though. You can probably search through the components owned by `Application` to find the instance. – David Heffernan Jun 22 '15 at 16:11
  • Or, you could take advantage of the fact that there is only ever one hint window instance. Declare a global variable of type TMyHintWindow. In the constructor, assign to that variable the reference of the new object. In the destructor, assign `nil`. When you need to change the font, you can gain access to the instance that way. – David Heffernan Jun 22 '15 at 16:19
  • This might get you started http://pastebin.com/cjD1yfWn. – TLama Jun 22 '15 at 16:56
  • I run the code and nothing happened. The hint appears in it's default font size. I assigned new values to `FMyHintData.FontSize` but nothing is changed. – Marus Gradinaru Jun 22 '15 at 17:33
  • There is another option to consider - derive a new component from `TCustomHint` and override its virtual `PaintHint()` method, then assign an instance of this component to the button's `CustomHint` property (`CM_HINTSHOW` is not issued when `TCustomHint` is used). `PaintHint()` is given a `TCustomHintWindow` object as input, which you can customize as needed. Have your `TCustomHint` component expose its own `Font` property that you can assign whenever you need to, and then `PaintHint()` can assign its current `Font` to the `Canvas.Font` of the provided `TCustomHintWindow`. – Remy Lebeau Jun 22 '15 at 17:49

3 Answers3

1

Since there is only one hint window instance at the time, and that instance will be created after call to CMHintShow, you can use class variables to do additional hint customization. Class variable is class member that is shared among all instances of the class and can be accessed directly through class type or class instance.

type
  TMyHintWindow = class(THintWindow)
  protected
    class constructor ClassCreate;
  public
    class var FontSize: integer;
    constructor Create(AOwner: TComponent); override;
  end;

class constructor TMyHintWindow.ClassCreate;
begin
  FontSize := 25;
end;

constructor TMyHintWindow.Create(AOwner: TComponent);
begin
  inherited;
  Canvas.Font.Size := FontSize;
end;

and then you can change FontSize in CMHintShow method

procedure TMyButton.CMHintShow(var Message: TCMHintShow);
begin
  inherited;
  TMyHintWindow.FontSize := 12;
  Message.HintInfo.HintWindowClass := TMyHintWindow;
  Message.HintInfo.HintStr := 'My custom hint';
end;
Dalija Prasnikar
  • 27,212
  • 44
  • 82
  • 159
1

Starting from indications given by TLama I finally solved this problem. The key was to set Canvas.Font.Size in TMyHintWindow.CalcHintRect.

Here is the code:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TMyHintData = record
    FontSize: Integer;
  end;

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

  TMyButton = class(TButton)
  private
    procedure CMHintShow(var AMessage: TCMHintShow); message CM_HINTSHOW;
  public
    FMyHintData: TMyHintData;
    constructor Create(AOwner: TComponent); override;
  end;

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    MyButton: TMyButton;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
 TMyButton(Sender).FMyHintData.FontSize:=44;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 MyButton:=TMyButton.Create(Form1);
 MyButton.Parent:=Form1;
 MyButton.Caption:='Test';
 MyButton.Left:=100;
 MyButton.Top:=100;
 MyButton.ShowHint:=true;
 MyButton.OnClick:=Button1Click;
end;

function TMyHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: string; AData: TCustomData): TRect;
begin
 Canvas.Font.Size:=TMyHintData(AData^).FontSize;
 Result:=inherited;
end;

constructor TMyButton.Create(AOwner: TComponent);
begin
 inherited;
 FMyHintData.FontSize:=25;
end;

procedure TMyButton.CMHintShow(var AMessage: TCMHintShow);
begin
 inherited;
 AMessage.HintInfo.HintData:=@FMyHintData;
 AMessage.HintInfo.HintWindowClass:=TMyHintWindow;
 AMessage.HintInfo.HintStr:='My custom hint';
end;

end.
Marus Gradinaru
  • 2,824
  • 1
  • 26
  • 55
0
procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.OnShowHint:=AppOnShowHint;
end;

procedure TForm1.AppOnShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo);
begin
  {Use HintInfo (type:THintInfo) to specify some property of hint-window}
  {For example: set hint-window width to the width of longest word in the hint-text}
  HintInfo.HintMaxWidth:=1;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  {Set HintFont at runtime}
  Screen.HintFont.Size:=strtoint(Edit1.Text);
  {It's necessary to recreate the Application.FHintWindow private variable, so:}
  Application.ShowHint:=False;
  Application.ShowHint:=True;
end;
bodzso
  • 1
  • 1