Recent

Author Topic: [SOLVED] anchors auto resize  (Read 9033 times)

mercury

  • Full Member
  • ***
  • Posts: 151
[SOLVED] anchors auto resize
« on: February 16, 2015, 09:36:34 am »
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.
« Last Edit: February 21, 2015, 12:44:10 pm by mercury »

howardpc

  • Hero Member
  • *****
  • Posts: 3210
Re: anchors auto resize
« Reply #1 on: February 16, 2015, 11:48:23 am »
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.

GetMem

  • Hero Member
  • *****
  • Posts: 3519
Re: anchors auto resize
« Reply #2 on: February 16, 2015, 12:23:14 pm »
@howardpc

Your forgot the resizing part, when the user resize the form. Other then that it's a nice and elegant solution.

howardpc

  • Hero Member
  • *****
  • Posts: 3210
Re: anchors auto resize
« Reply #3 on: February 16, 2015, 12:39:43 pm »
Yes, OnResize event left as an exercise for the OP - he's got the basic algorithm already.

Blaazen

  • Hero Member
  • *****
  • Posts: 2782
  • POKE 54296,15
    • Eye-Candy Controls
Re: anchors auto resize
« Reply #4 on: February 16, 2015, 12:50:20 pm »
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.
Lazarus 2.1.0 r61214:62238 FPC 3.3.1 r40507 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

howardpc

  • Hero Member
  • *****
  • Posts: 3210
Re: anchors auto resize
« Reply #5 on: February 16, 2015, 01:16:27 pm »
Isn't it easy when you know how?

mercury

  • Full Member
  • ***
  • Posts: 151
Re: anchors auto resize
« Reply #6 on: February 17, 2015, 03:11:59 am »
@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.
« Last Edit: February 17, 2015, 04:04:00 am by mercury »

Blaazen

  • Hero Member
  • *****
  • Posts: 2782
  • POKE 54296,15
    • Eye-Candy Controls
Re: anchors auto resize
« Reply #7 on: February 17, 2015, 12:40:24 pm »
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.
Lazarus 2.1.0 r61214:62238 FPC 3.3.1 r40507 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

mercury

  • Full Member
  • ***
  • Posts: 151
Re: anchors auto resize
« Reply #8 on: February 18, 2015, 03:48:31 am »
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.
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 "<table>" in HTML.
In GTK there is "table's boxes", and in wxWidgets there is "wxGridSizer".
Is there same thing in LCL?

Mike.Cornflake

  • Hero Member
  • *****
  • Posts: 1250
Re: anchors auto resize
« Reply #9 on: February 18, 2015, 07:42:45 am »
Quote
In 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
Lazarus Trunk/FPC Trunk on Windows [7, 10]
  Have you tried searching this forum or the wiki?:   http://wiki.lazarus.freepascal.org/Alternative_Main_Page
  BOOKS! (Free and otherwise): http://wiki.lazarus.freepascal.org/Pascal_and_Lazarus_Books_and_Magazines

mercury

  • Full Member
  • ***
  • Posts: 151
Re: anchors auto resize
« Reply #10 on: February 21, 2015, 12:42:17 pm »
Quote
In 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

  • Newbie
  • Posts: 3
Re: [SOLVED] anchors auto resize
« Reply #11 on: September 19, 2015, 05:43:18 pm »
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

  • Hero Member
  • *****
  • Posts: 3210
Re: [SOLVED] anchors auto resize
« Reply #12 on: September 19, 2015, 07:28:21 pm »
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

  • Newbie
  • Posts: 3
Re: [SOLVED] anchors auto resize
« Reply #13 on: September 20, 2015, 05:17:42 pm »
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

  • Full Member
  • ***
  • Posts: 151
Re: [SOLVED] anchors auto resize
« Reply #14 on: September 27, 2015, 02:44:31 pm »
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;

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;



« Last Edit: September 27, 2015, 02:46:47 pm by mercury »