[SOLVED] anchors auto resize lazarus / 10-Designer ---------------------------------------------------------------------- mercury · 2015-02-16 08:36 I made a form like pic1. And want the form auto resize like pic2. So I set anchors like pic3. But it auto resize like pic4. How can I make it auto resize like pic2? Thank for you help. ---------------------------------------------------------------------- howardpc · 2015-02-16 10:48 I don't know of an easy way to do this using the Form Designer (though there may well be one). You can achieve this in code thus: Code: [Select]unit LayoutButtons; {$mode objfpc}{$H+} interface uses   Classes, SysUtils, Forms, StdCtrls; type   TBtnRange = 1..6;   TBArray = array[TBtnRange] of TButton;   { TForm1 }   TForm1 = class(TForm)     procedure FormCreate(Sender: TObject);   private     FButtons: TBArray;   end; var   Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject); var   i: integer;   hw: TPoint;   function NewButton(anIdx: integer): TButton;   var     r, c: integer;   begin     r:=(anIdx-1) div 3;     c:=(anIdx-1) mod 3;     Result:=TButton.Create(Self);     Result.AutoSize:=False;     Result.Name:=Format('FButtons_%d',[anIdx]);     Result.SetBounds(c*hw.x-(c+1), r*hw.y-(r+1), hw.x, hw.y);     Result.Parent:=Self;   end;   function GetHW: TPoint;   begin     Result.x:=ClientWidth div 3;     Result.y:=ClientHeight div 2;   end; begin   hw:=GetHW;   for i in TBtnRange do     FButtons[i]:=NewButton(i);   Height:=FButtons[High(TBtnRange)].BoundsRect.Bottom;   Width:=FButtons[High(TBtnRange)].BoundsRect.Right; end; end. ---------------------------------------------------------------------- balazsszekely · 2015-02-16 11:23 @howardpc Your forgot the resizing part, when the user resize the form. Other then that it's a nice and elegant solution. ---------------------------------------------------------------------- howardpc · 2015-02-16 11:39 Yes, OnResize event left as an exercise for the OP - he's got the basic algorithm already. ---------------------------------------------------------------------- Blaazen · 2015-02-16 11:50 Do not use Anchor nor OnResize event. Lazarus can do it. Open ChildSizing property of the form and set: ControlsPerLine := 3; Layout := cclLeftToRightThenTopToBottom; and all Shrink/EnlargeVertical/Horizontal := crsHomogenousChildResize; And you have it. ---------------------------------------------------------------------- howardpc · 2015-02-16 12:16 Isn't it easy when you know how? ---------------------------------------------------------------------- mercury · 2015-02-17 02:11 @howardpc Thanks. Your code is working. But I want the button auto resize(when form resize) not auto create. And I don't want code in OnResize event, it's a trouble when the form contains lots of widget(not just button, also many other types). @Blaazen Yes, your method is what I need, thank you. But when I add a button in panel, look picA. Panel1 is biger than others. How to make them all same size. In other words, I want zoom the whole form like zoom a photo when form resize. ---------------------------------------------------------------------- Blaazen · 2015-02-17 11:40 Interesting, I didn't noticed this before. I have solution: remove all anchors of the button on the panel ( Anchors := [ ]; ) and resize the form a little. ---------------------------------------------------------------------- mercury · 2015-02-18 02:48 Quote from: Blaazen on February 17, 2015, 12:40:24 pmInteresting, I didn't noticed this before. I have solution: remove all anchors of the button on the panel ( Anchors := [ ]; ) and resize the form a little. But widgets in panel will not auto resize. Is there any way to set "Width", "Height", "Top" and "Left" in "%" not in "px".Some thing like "" in HTML. In GTK there is "table's boxes", and in wxWidgets there is "wxGridSizer". Is there same thing in LCL? ---------------------------------------------------------------------- Mike.Cornflake · 2015-02-18 06:42 QuoteIn GTK there is "table's boxes", and in wxWidgets there is "wxGridSizer". Is there same thing in LCL? Not that I'm aware of. Does this help? http://wiki.lazarus.freepascal.org/Autosize_/_Layout ---------------------------------------------------------------------- mercury · 2015-02-21 11:42 Quote from: Mike.Cornflake on February 18, 2015, 07:42:45 amQuoteIn GTK there is "table's boxes", and in wxWidgets there is "wxGridSizer". Is there same thing in LCL? Not that I'm aware of. Does this help? http://wiki.lazarus.freepascal.org/Autosize_/_Layout Seems LCL doesn't provide a way like "table's boxes" which GTK does. But I find a way to do this. Code: [Select]var   Form1: TForm1;   AutoZoom: array of array of real; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject); var   i, j: integer; begin   SetLength(AutoZoom, Self.ControlCount, 4);   for i := 0 to Self.ControlCount - 1 do   begin     AutoZoom[i][0] := Self.Controls[i].Top / Self.Height;     AutoZoom[i][1] := Self.Controls[i].Left / Self.Width;     AutoZoom[i][2] := Self.Controls[i].Width / Self.Width;     AutoZoom[i][3] := Self.Controls[i].Height / Self.Height;   end; end; procedure TForm1.FormResize(Sender: TObject); var   i: integer; begin   for i := 0 to Form1.ControlCount - 1 do   begin     Self.Controls[i].Top := Round(AutoZoom[i][0] * Self.Height);     Self.Controls[i].Left := Round(AutoZoom[i][1] * Self.Width);     Self.Controls[i].Width := Round(AutoZoom[i][2] * Self.Width);     Self.Controls[i].Height := Round(AutoZoom[i][3] * Self.Height);   end; end; Thank you. ---------------------------------------------------------------------- dsw1 · 2015-09-19 15:43 I used the code and it works very good to resize my form but I am struggling to resize fonts. Any idea's on how this can be done? ---------------------------------------------------------------------- howardpc · 2015-09-19 17:28 A possible approach would be to drop a label somewhere on your form named LDummy, and then use some variation on the following: Code: [Select]procedure TForm1.FormCreate(Sender: TObject); var   i: integer; begin   LDummy.Left:=ClientWidth + 1;   SetLength(AutoZoom, Self.ControlCount, 4);   for i := 0 to Self.ControlCount - 1 do   begin     AutoZoom[i][0] := Self.Controls[i].Top / Self.Height;     AutoZoom[i][1] := Self.Controls[i].Left / Self.Width;     AutoZoom[i][2] := Self.Controls[i].Width / Self.Width;     AutoZoom[i][3] := Self.Controls[i].Height / Self.Height;   end; end; procedure TForm1.FormResize(Sender: TObject); var   i, initialSize: integer;   procedure AdjustFontSize(aLabelHeight: integer);   var     textHeight: byte;     targetHeight: byte;   begin     textHeight:=LDummy.Canvas.TextHeight(LDummy.Caption);     targetHeight:=aLabelHeight;     if (textHeight < targetHeight) then       repeat         LDummy.Font.Size:=LDummy.Font.Size + 1;         textHeight:=LDummy.Canvas.TextHeight(LDummy.Caption);       until (textHeight in [Pred(targetHeight), targetHeight, Succ(targetHeight)])     else if (textHeight > targetHeight) then       repeat         LDummy.Font.Size:=LDummy.Font.Size - 1;         textHeight:=LDummy.Canvas.TextHeight(LDummy.Caption);       until (textHeight in [Pred(targetHeight), targetHeight, Succ(targetHeight)])   end; begin   DisableAlign;   for i := 0 to Form1.ControlCount - 1 do   begin     Self.Controls[i].Top := Round(AutoZoom[i][0] * Self.Height);     Self.Controls[i].Left := Round(AutoZoom[i][1] * Self.Width);     Self.Controls[i].Width := Round(AutoZoom[i][2] * Self.Width);     Self.Controls[i].Height := Round(AutoZoom[i][3] * Self.Height);   end;   initialSize:=LDummy.Font.Size;   if (LDummy.Height <> LDummy.Canvas.TextHeight(LDummy.Caption)) then     AdjustFontSize(LDummy.Height);   if (LDummy.Font.Size <> initialSize) then     for i:=0 to form1.ControlCount-1 do       if (Controls[i] <> LDummy) then         Controls[i].Font.Size:=LDummy.Font.Size;   EnableAlign; end; ---------------------------------------------------------------------- dsw1 · 2015-09-20 15:17 Thanks I can work with it. I have forms containing different font sizes. I fixed that by calculating their relative size in relation to LDummy ---------------------------------------------------------------------- mercury · 2015-09-27 12:44 Quote from: howardpc on September 19, 2015, 07:28:21 pmA possible approach would be to drop a label somewhere on your form named LDummy, and then use some variation on the following: Code: [Select]procedure TForm1.FormCreate(Sender: TObject); var   i: integer; begin   LDummy.Left:=ClientWidth + 1;   SetLength(AutoZoom, Self.ControlCount, 4);   for i := 0 to Self.ControlCount - 1 do   begin     AutoZoom[i][0] := Self.Controls[i].Top / Self.Height;     AutoZoom[i][1] := Self.Controls[i].Left / Self.Width;     AutoZoom[i][2] := Self.Controls[i].Width / Self.Width;     AutoZoom[i][3] := Self.Controls[i].Height / Self.Height;   end; end; procedure TForm1.FormResize(Sender: TObject); var   i, initialSize: integer;   procedure AdjustFontSize(aLabelHeight: integer);   var     textHeight: byte;     targetHeight: byte;   begin     textHeight:=LDummy.Canvas.TextHeight(LDummy.Caption);     targetHeight:=aLabelHeight;     if (textHeight < targetHeight) then       repeat         LDummy.Font.Size:=LDummy.Font.Size + 1;         textHeight:=LDummy.Canvas.TextHeight(LDummy.Caption);       until (textHeight in [Pred(targetHeight), targetHeight, Succ(targetHeight)])     else if (textHeight > targetHeight) then       repeat         LDummy.Font.Size:=LDummy.Font.Size - 1;         textHeight:=LDummy.Canvas.TextHeight(LDummy.Caption);       until (textHeight in [Pred(targetHeight), targetHeight, Succ(targetHeight)])   end; begin   DisableAlign;   for i := 0 to Form1.ControlCount - 1 do   begin     Self.Controls[i].Top := Round(AutoZoom[i][0] * Self.Height);     Self.Controls[i].Left := Round(AutoZoom[i][1] * Self.Width);     Self.Controls[i].Width := Round(AutoZoom[i][2] * Self.Width);     Self.Controls[i].Height := Round(AutoZoom[i][3] * Self.Height);   end;   initialSize:=LDummy.Font.Size;   if (LDummy.Height <> LDummy.Canvas.TextHeight(LDummy.Caption)) then     AdjustFontSize(LDummy.Height);   if (LDummy.Font.Size <> initialSize) then     for i:=0 to form1.ControlCount-1 do       if (Controls[i] <> LDummy) then         Controls[i].Font.Size:=LDummy.Font.Size;   EnableAlign; end; Sorry, I don't understand your code. It doesn't work for me. The font size keep growing when I resize the form, no matter the form is big or small. And why call DisableAlign? Is that matter? BTW, I think this way is easier. @dsw1 Code: [Select]var   Form1: TForm1;   AutoZoom: array of array of real;   FormAspect: real; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject); var   i, j: integer; begin   FormAspect := Self.Width / Self.Height;   SetLength(AutoZoom, Self.ControlCount, 6);   for i := 0 to Self.ControlCount - 1 do   begin     AutoZoom[i][0] := Self.Controls[i].Top / Self.Height;     AutoZoom[i][1] := Self.Controls[i].Left / Self.Width;     AutoZoom[i][2] := Self.Controls[i].Width / Self.Width;     AutoZoom[i][3] := Self.Controls[i].Height / Self.Height;     if Self.Controls[i].Font.Height = 0 then       Self.Controls[i].Font.Height := 24;     AutoZoom[i][4] := Self.Controls[i].Font.Height / Self.Width;     AutoZoom[i][5] := Self.Controls[i].Font.Height / Self.Height;   end; end; procedure TForm1.FormResize(Sender: TObject); var   i: integer; begin   for i := 0 to Form1.ControlCount - 1 do   begin     Self.Controls[i].Top := Round(AutoZoom[i][0] * Self.Height);     Self.Controls[i].Left := Round(AutoZoom[i][1] * Self.Width);     Self.Controls[i].Width := Round(AutoZoom[i][2] * Self.Width);     Self.Controls[i].Height := Round(AutoZoom[i][3] * Self.Height);     if Self.Width / Self.Height < FormAspect then       Self.Controls[i].Font.Height := Round(AutoZoom[i][4] * Self.Width)     else       Self.Controls[i].Font.Height := Round(AutoZoom[i][4] * Self.Height);   end; end; ---------------------------------------------------------------------- derek.john.evans · 2015-09-27 14:50 Interesting concept. Here is an alternative to caching percentages for each control. You can use TControl.ReadBounds to get the original bounds of the control. Usage: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.FormResize(Sender: TObject);begin  WinControlProportionalResizer(Self);end;   Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure WinControlProportionalResizer(const AParent: TWinControl);var  LReadBounds, LParentReadBounds: TRect;  LIndex, LReadWidth, LReadHeight, LParentReadWidth, LParentReadHeight: Integer;  LControl: TControl;begin  for LIndex := 0 to AParent.ControlCount - 1 do begin  LControl := AParent.Controls[LIndex];    if LControl.Align = alNone then begin      LReadBounds := LControl.ReadBounds;      LReadWidth := LReadBounds.Right - LReadBounds.Left;      LReadHeight := LReadBounds.Bottom - LReadBounds.Top;      LParentReadBounds := AParent.ReadBounds;      LParentReadWidth := LParentReadBounds.Right - LParentReadBounds.Left;      LParentReadHeight := LParentReadBounds.Bottom - LParentReadBounds.Top;      LControl.SetBounds(LReadBounds.Left * AParent.Width div LParentReadWidth,        LReadBounds.Top * AParent.Height div LParentReadHeight,        LReadWidth * AParent.Width div LParentReadWidth,        LReadHeight * AParent.Height div LParentReadHeight);      if LControl is TCustomButton then begin      LControl.Font.Height := LControl.Height - 2;      end;    end;  end;end; Note: I'm not sure I coded the same font sizing, but, anyway, see what you think. ---------------------------------------------------------------------- AlphaInc. · 2021-04-22 10:22 Quote from: mercury on September 27, 2015, 02:44:31 pmQuote from: howardpc on September 19, 2015, 07:28:21 pmA possible approach would be to drop a label somewhere on your form named LDummy, and then use some variation on the following: Code: [Select]procedure TForm1.FormCreate(Sender: TObject); var   i: integer; begin   LDummy.Left:=ClientWidth + 1;   SetLength(AutoZoom, Self.ControlCount, 4);   for i := 0 to Self.ControlCount - 1 do   begin     AutoZoom[i][0] := Self.Controls[i].Top / Self.Height;     AutoZoom[i][1] := Self.Controls[i].Left / Self.Width;     AutoZoom[i][2] := Self.Controls[i].Width / Self.Width;     AutoZoom[i][3] := Self.Controls[i].Height / Self.Height;   end; end; procedure TForm1.FormResize(Sender: TObject); var   i, initialSize: integer;   procedure AdjustFontSize(aLabelHeight: integer);   var     textHeight: byte;     targetHeight: byte;   begin     textHeight:=LDummy.Canvas.TextHeight(LDummy.Caption);     targetHeight:=aLabelHeight;     if (textHeight < targetHeight) then       repeat         LDummy.Font.Size:=LDummy.Font.Size + 1;         textHeight:=LDummy.Canvas.TextHeight(LDummy.Caption);       until (textHeight in [Pred(targetHeight), targetHeight, Succ(targetHeight)])     else if (textHeight > targetHeight) then       repeat         LDummy.Font.Size:=LDummy.Font.Size - 1;         textHeight:=LDummy.Canvas.TextHeight(LDummy.Caption);       until (textHeight in [Pred(targetHeight), targetHeight, Succ(targetHeight)])   end; begin   DisableAlign;   for i := 0 to Form1.ControlCount - 1 do   begin     Self.Controls[i].Top := Round(AutoZoom[i][0] * Self.Height);     Self.Controls[i].Left := Round(AutoZoom[i][1] * Self.Width);     Self.Controls[i].Width := Round(AutoZoom[i][2] * Self.Width);     Self.Controls[i].Height := Round(AutoZoom[i][3] * Self.Height);   end;   initialSize:=LDummy.Font.Size;   if (LDummy.Height <> LDummy.Canvas.TextHeight(LDummy.Caption)) then     AdjustFontSize(LDummy.Height);   if (LDummy.Font.Size <> initialSize) then     for i:=0 to form1.ControlCount-1 do       if (Controls[i] <> LDummy) then         Controls[i].Font.Size:=LDummy.Font.Size;   EnableAlign; end; Sorry, I don't understand your code. It doesn't work for me. The font size keep growing when I resize the form, no matter the form is big or small. And why call DisableAlign? Is that matter? BTW, I think this way is easier. @dsw1 Code: [Select]var   Form1: TForm1;   AutoZoom: array of array of real;   FormAspect: real; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject); var   i, j: integer; begin   FormAspect := Self.Width / Self.Height;   SetLength(AutoZoom, Self.ControlCount, 6);   for i := 0 to Self.ControlCount - 1 do   begin     AutoZoom[i][0] := Self.Controls[i].Top / Self.Height;     AutoZoom[i][1] := Self.Controls[i].Left / Self.Width;     AutoZoom[i][2] := Self.Controls[i].Width / Self.Width;     AutoZoom[i][3] := Self.Controls[i].Height / Self.Height;     if Self.Controls[i].Font.Height = 0 then       Self.Controls[i].Font.Height := 24;     AutoZoom[i][4] := Self.Controls[i].Font.Height / Self.Width;     AutoZoom[i][5] := Self.Controls[i].Font.Height / Self.Height;   end; end; procedure TForm1.FormResize(Sender: TObject); var   i: integer; begin   for i := 0 to Form1.ControlCount - 1 do   begin     Self.Controls[i].Top := Round(AutoZoom[i][0] * Self.Height);     Self.Controls[i].Left := Round(AutoZoom[i][1] * Self.Width);     Self.Controls[i].Width := Round(AutoZoom[i][2] * Self.Width);     Self.Controls[i].Height := Round(AutoZoom[i][3] * Self.Height);     if Self.Width / Self.Height < FormAspect then       Self.Controls[i].Font.Height := Round(AutoZoom[i][4] * Self.Width)     else       Self.Controls[i].Font.Height := Round(AutoZoom[i][4] * Self.Height);   end; end; Hey, I know it's been a long time since the last reply in this topic but do you happen to know how to apply this on a TNotebook? Whenever I scale it, the buttons on a TNotebook Page stay fixed and therefore are out of the screen.