Resize all controls when the parent form is resized (Views: 31)
Problem/Question/Abstract: How to resize all controls when the parent form is resized Answer: I would like to describe a technique I used in order to resize (with recursion) all the child controls of a TForm when the user resizes the form itself. I think it works relatively well, at least for my requirements. The key is the implementation of the OnResize event of the TForm. Every time the TForm is resized we chnage from an initial height PH to a final height HH and from an initial width PW to a final width WW. At the very beginning (for example in the OnCreate event) we register the value of PW and PH: Form1.FormCreate(Sender: TObject); begin { ... } PW := Form1.ClientWidth; PH := Form1.ClientHeight; { ... } end; Then in the implementation of the OnResize event we have: Form1.FormResize(Sender: TObject); begin WW := Form1.ClientWidth; {new value of width after the resizing} HH := Form1.ClientHeight; {new value of height after the resizing} {put your cyclically resizing code here} {actual dimension: they will be the old dimensions in the next resizing } PW := WW; PH := HH; end; Now let's go deep into details with the cyclically resizing code. This is the code we place inside the implementation of the OnResize event of the TForm: { ... } for I := 0 to (Form1.ControlCount - 1) do begin ChangeDims(Form1.Controls[i], WW, PW, HH, PH); end; "ChangeDims" is the procedure which resizes (with recursion) the child controls. procedure ChangeDims(Control: TControl; WW, PW, HH, PH: Integer); var L, T, W, H: integer; begin if Control is TWinControl then (Control as TWinControl).DisableAlign; try if Control is TWinControl then ScaleCtrls(Control as TWinControl, WW, PW, HH, PH); L := MulDiv(Control.Left, WW, PW); T := MulDiv(Control.Top, HH, PH); W := MulDiv(Control.Left + Control.Width, WW, PW) - L; H := MulDiv(Control.Top + Control.Height, HH, PH) - T; Control.SetBounds(L, T, W, H); finally if Control is TWinControl then (Control as TWinControl).DisableAlign; end; end; procedure ScaleCtrls(Control: TWinControl; WW, PW, HH, PH: Integer); var I: Integer; begin for I := 0 to Control.ControlCount - 1 do ChangeDims(Control.Controls[i], WW, PW, HH, PH); end; By making the above mentioned changes to your Form you can achieve the autoresizing of all child controls on a form. After verifing the validity of the code I encapsulated its functionality in a component. I didn't want to fill every time with extra code my form's implementation: I wanted to drop a component to my form and stop. This component assign the implementation of the OnResize event of the form after having assigned the aventually already present OnResize implementation. As a consequence the OnResize event of the Form will consist in the call to the user defined implementation (if any) followed by the above mentioned implementation which is responsible for the resizing. In this way you can assign your implementation to the OnResize event of the Form avoiding its hiding because of the presence of the cyclically resizing code. Here is the complete code for the component: unit Resize; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; type { THackControl = class(TControl); } TResize = class(TComponent) private { Private declarations } FForm1: TForm; PW, PH: integer; FOnResizeEvent: TNotifyEvent; procedure ScaleCtrls(Control: TWinControl; WW, PW, HH, PH: Integer); procedure ChangeDims(Control: TControl; WW, PW, HH, PH: Integer); procedure OnResizeEvent(Sender: TObject); procedure Resize(); protected { Protected declarations } public { Public declarations } constructor Create(AOwner: TComponent); override; destructor Destroy(); override; published { Published declarations } end; procedure Register; implementation constructor TResize.Create(AOwner: TComponent); begin inherited Create(AOwner); if csDesigning in ComponentState then Exit; FForm1 := (Owner as TForm); PW := FForm1.ClientWidth; PH := FForm1.ClientHeight; if Assigned(FForm1.OnResize) then begin FOnResizeEvent := FForm1.OnResize; end; FForm1.OnResize := OnResizeEvent; end; destructor TResize.Destroy(); begin if not (csDesigning in ComponentState) then FForm1.OnResize := FOnResizeEvent; inherited Destroy(); end; procedure TResize.ScaleCtrls(Control: TWinControl; WW, PW, HH, PH: Integer); var I: Integer; begin for I := 0 to Control.ControlCount - 1 do ChangeDims(Control.Controls[i], WW, PW, HH, PH); end; procedure TResize.ChangeDims(Control: TControl; WW, PW, HH, PH: Integer); var L, T, W, H: integer; begin if Control is TWinControl then (Control as TWinControl).DisableAlign; try if Control is TWinControl then ScaleCtrls(Control as TWinControl, WW, PW, HH, PH); L := MulDiv(Control.Left, WW, PW); T := MulDiv(Control.Top, HH, PH); W := MulDiv(Control.Left + Control.Width, WW, PW) - L; H := MulDiv(Control.Top + Control.Height, HH, PH) - T; { THackControl(Control).Font.Size := (PW div WW) * THackControl(Control).Font.Size;} Control.SetBounds(L, T, W, H); finally if Control is TWinControl then (Control as TWinControl).DisableAlign; end; end; procedure TResize.OnResizeEvent(Sender: TObject); begin if Assigned(FOnResizeEvent) then begin FOnResizeEvent(Sender); end; Resize(); end; procedure TResize.Resize(); var L, T, R, B, W, H, WW, HH, I: Integer; begin WW := FForm1.ClientWidth; HH := FForm1.ClientHeight; for I := 0 to (FForm1.ControlCount - 1) do begin ChangeDims(FForm1.Controls[i], WW, PW, HH, PH); end; PW := WW; PH := HH; end; procedure Register; begin RegisterComponents('Carlo Pasolini', [TResize]); end; end. |