简体   繁体   中英

Delphi - Open window at location of a TLabel

I have two forms, Form1 and Form2 I have a TLabel on Form1 which an onclick event which calls Form2.show;

What I am trying to do, if figure out how I can make form2 show 5px below the label centered between the label :) Form2 is small and just shows some options.

I can use the mouse position but it's not quite good enough.

I was thinking something like

// Set top - add 20 for the title bar of software
Form2.Top := Form1.Top + Label1.Top + Label1.Height + 20;
// Set the Left
Form2.Left := Form1.Left + Label1.Left + round(Label1.Width / 2) - round(form2.Width/2);

but I think there can be a better way

You need to set the coordinates for Form2 using the coordinate system of it's Parent. Assuming the Parent is the Desktop (since you're attempting to compensate for the height of the title bar), this can do it:

procedure ShowForm;
var P: TPoint;
begin
  // Get the top-left corner of the Label in *screen coordinates*. This automatically compensates
  // for whatever height the non-client area of the window has.
  P := Label1.ScreenToClient(Label1.BoundsRect.TopLeft);
  // Assign the coordinates of Form2 based on the translated coordinates (P)
  Form2.Top := P.Y + 5; // You said you want it 5 pixels lower
  Form2.Left := P.X + 5 + (Label1.Width div 2); // Use div since you don't care about the fractional part of the division
end;

You'll need to adapt the code for the positioning of Form2 based on your centering requirement, I didn't quite understand what you want. And of course, if a frame or panel is enough, it's better! Take a good look at Guillem's solution.

procedure TForm2.AdjustPosition(ARefControl: TControl);
var
  LRefTopLeft: TPoint;
begin
  LRefTopLeft := ARefControl.ScreenToClient(ARefControl.BoundsRect.TopLeft);

  Self.Top := LRefTopLeft.Y + ARefControl.Height + 5;
  Self.Left := LRefTopLeft.X + ((ARefControl.Width - Self.Width) div 2);
end;

Then you can have the form adjust itself relative to any desired control as follows:

Form2.AdjustPosition(Form1.Label1);

Do you really need Form2 to be a form? You could choose to create a frame containing the Form2 logic and use a hidden TPanel as its parent. When the user clicks on the Label1 you show then the panel.

Something like following. When you create Form1 or when you click on Label1 (depending on your needs):

 Frame := TFrame1.Create(Self);
 Frame.Parent := Panel1;

In the OnClick event for Label1:

Panel1.Top  := Label1.Top + 5;
Panel1.Left := Label1.Left + round(Label1.Width / 2) - round(form2.Width/2);
Panel1.Visible := true;

When the user is done just hide the panel again (and destroy the Frame if necessary). If you keep the Frame alive while the user is using Form1 remember to free it when leaving the form.

HTH

The ClientOrigin property will return the lebel's upper-left corner in screen coordinates, so you do not need to determine it manually:

var
  Pt: TPoint;
begin
  Pt := Label1.ClientOrigin;
  Form2.Left := Pt.X + Round(Label1.Width / 2) - Round(Form2.Width/2); 
  Form2.Top := Pt.Y + Label1.Height + 5;
end;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM