2008. január 3., csütörtök
Resize all controls when the parent form is resized
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.
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése