Uli Gerhardt
Uli Gerhardt

Reputation: 14001

Equivalent to designer guidelines in code

The VCL form designer offers pink guidelines for aligning controls at their respective text base lines: Guidelines in form designer
But as far as I can tell this doesn't work for labels and checkboxes. Update: It works for labels if you place the controls exactly, e.g. by Ctrl-arrow. It kind of works for checkboxes - see screenshot.

Now, on some forms I'm creating controls in code, e.g.

ed := TEdit.Create(Self);
ed.SetBounds(...);
ed.Parent := SomePanel;

etc. How can I ensure that their text base lines are aligned? I'd like to have this for edits, comboboxes, labels and checkboxes. The result should look like this (without the red line, of course :-)): base line aligned

Edit: My current approach is to call something like AlignTop(8, [Edit1, ComboBox1], [CheckBox1, Label1]); with

procedure ControlArray_SetTop(const AControls: array of TControl; ATop: Integer);
var
  i: Integer;
begin
  for i := Low(AControls) to High(AControls) do
    AControls[i].Top := ATop;
end;

procedure AlignTop(ATop: Integer; const AControls: array of TControl; const ALabelLikeControls: array of TControl);
begin
  ControlArray_SetTop(AControls, ATop);
  ControlArray_SetTop(ALabelLikeControls, ATop + 3);
end;

My goal is to replace it with something more robust and less hacky.

Upvotes: 11

Views: 757

Answers (4)

John Kouraklis
John Kouraklis

Reputation: 686

If you make the two controls of the same height, align the tops and align the text vertically normally the base line will be aligned even when you change font size and fonts

Upvotes: 0

X-Ray
X-Ray

Reputation: 2846

i wanted to align a label to it's edit box. standing on @ain's shoulders, i used this:

  Label1.Top := edit1.Top + _GetTextBaseline(edit1, tlBottom) - _GetTextBaseline(Label1, tlTop);


  // lifted from TControlGuidelines.GetTextBaseline(AControl: TControl; Align: TTextLayout): Integer;
  function _GetTextBaseline(AControl: TControl; Align: TTextLayout): Integer;
  var
    Canvas: TControlCanvas;
    tm: TTextMetric;
    ClientRect: TRect;
    Ascent, Height: Integer;
  begin
    Canvas := TControlCanvas.Create;
    try
      ClientRect := AControl.ClientRect;
      Canvas.Control := AControl;
      Canvas.Font := TControlFriend(AControl).Font;
      GetTextMetrics(Canvas.Handle, tm);
      Ascent := tm.tmAscent + 1;
      Height := tm.tmHeight;
      case Align of
        tlTop: Result := ClientRect.Top + Ascent;
        tlCenter: Result := (ClientRect.Top + (ClientRect.Bottom - Height) div 2) + Ascent;
        tlBottom: Result := (ClientRect.Bottom - Height) + Ascent;
      else
        Result := 0;
      end;
    finally
      Canvas.Free;
    end;
  end;

Upvotes: 1

ain
ain

Reputation: 22759

The guidelines are implemented in designtime code which license prohibits you to ship with your app so you can only use it to learn from it and then reimplement it yourself. Look up

DesignIntf.TBaseComponentGuidelines
DesignEditors.TComponentGuidelines
VCLEditors.TControlGuidelines

classes (in "{RADStudio\version}\source\ToolsAPI directory"). Perhaps it comes down to something simple as

Label1.Top := (Edit1.Top + Edit1.Height) - Label1.Height + GetMagicConstant;  

where GetMagicConstant is similar to TControlGuidelines.GetTextBaseline().

Upvotes: 5

David Heffernan
David Heffernan

Reputation: 612993

I don't think this logic is exposed in any way for you to call at runtime. I believe it is design time only.

To handle this I would create a dummy form in the designer which had one of each control you worked with. Align them all the way you have in your screenshots. At runtime instantiate this form, but don't show it and read out the Top property for each type of control. Finally you can work out the vertical offset of the Top property from each type of control to each other type of control.

Upvotes: 2

Related Questions