[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.