9

I am trying to create a THintWindow and place a TButton or a TFrame on it. here is my code:

TForm1 = class(TForm)
  Button1: TButton;
  Button2: TButton;
  procedure FormCreate(Sender: TObject);
  procedure Button1Click(Sender: TObject);
  procedure Button2Click(Sender: TObject);
private
  HintWindow: THintWindow;
public
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  HintWindow := THintWindow.Create(Self);
  HintWindow.Color := clInfoBk;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  P: TPoint;
  R: TRect;
  Control: TControl;
begin
  Control := Button1;
  P := Control.ClientToScreen(Point(0, Control.Height));
  R := Rect(P.X, P.Y, P.x + 100, P.Y + 100);
  with TButton.Create(HintWindow) do
  begin
    Parent := HintWindow;
    Caption := 'My Button';
  end;
  HintWindow.ActivateHint(R, 'My Hint');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  HintWindow.ReleaseHandle;
end;

The Hint window is shown but I don't see the TButton. it seems that there are no child windows inside the Hint window (I tested with Spy++ for "first child"). I also tried to subclass THintWindow with new CreateParams ie:

procedure TMyHintWindow.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.Style := Params.Style or WS_CLIPCHILDREN;
  Params.ExStyle := Params.ExStyle or WS_EX_CONTROLPARENT;
end;

When I create a TFrame as child on the Hint window, Spy++ shows that there is a child on the hint window but I cant see it (even after I force it to be visible).

Any feed-backs on this?

kobik
  • 21,001
  • 4
  • 61
  • 121
  • That code works perfectly for me, no need for subclassing. What version of Delphi do you have? – David Heffernan Nov 17 '11 at 12:03
  • @David Heffernan: Can you see that Button? I use D5. – kobik Nov 17 '11 at 12:07
  • 1
    D5. Urgh! Yes, I'm on XE2 and I can see the button perfectly well. – David Heffernan Nov 17 '11 at 12:08
  • David, will it be too much to ask the source code of "THintWindow.Create" and "THintWindow.CreateParams" in your controls unit? – kobik Nov 17 '11 at 12:16
  • I've got D6. I'll have a dig there and see if I can see the behaviour you report. If so then it should be easy for me to work out what the diff is. – David Heffernan Nov 17 '11 at 12:21
  • I can repro your behaviour in D6 and using the XE2 code in D6 makes the button appear. I'll continue searching. – David Heffernan Nov 17 '11 at 12:35
  • @David, I have added: if Assigned(Screen.Activeform) then HintWindow.ParentWindow := Screen.ActiveForm.Handle else HintWindow.ParentWindow := Application.Handle; before "ActivateHint" and it seems to work for me now. Maybe that is what's missing in the controls unit on the ActivateHint? – kobik Nov 17 '11 at 12:47
  • 2
    It seems that you and I came up with the same answer at the same time! I studied XE2 source code and the most obvious difference that jumped out was the setting of ParentWindow which there happens in `ActivateHint`. The XE2 code always sets it to Application.Handle so I think that's just the simplest approach. No need to try to set it to `ActiveForm.Handle`. – David Heffernan Nov 17 '11 at 12:58

1 Answers1

11

Don't ask me why, but you can make this work in old versions of Delphi by setting the ParentWindow to Application.Handle immediately after you create the THintWindow instance:

HintWindow := THintWindow.Create(Self);
HintWindow.ParentWindow := Application.Handle;

This answer was inspired by the modern versions of the Delphi VCL source.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490