in the middle of the application is a frame. After resizing i need to rearrange controls on this panel (doing this in the resizing event is too busy). Its more useful if this can be done once after all the resizing. But how?
Thank you for your help
The trick is to hook into message processing of the parent form (proof-of-concept code, tested with Delphi 2009, error and corner case handling need more work):
type
TFrame2 = class(TFrame)
strict private
fOnEnterSizeMove: TNotifyEvent;
fOnExitSizeMove: TNotifyEvent;
fSavedWndProc: TWndMethod;
procedure DoEnterSizeMove;
procedure DoExitSizeMove;
procedure ParentWindowProc(var AMessage: TMessage);
protected
procedure CreateWnd; override;
procedure DestroyWnd; override;
published
property OnEnterSizeMove: TNotifyEvent read fOnEnterSizeMove
write fOnEnterSizeMove;
property OnExitSizeMove: TNotifyEvent read fOnExitSizeMove
write fOnExitSizeMove;
end;
{ TFrame2 }
procedure TFrame2.CreateWnd;
var
ParentForm: TCustomForm;
begin
inherited;
ParentForm := GetParentForm(Self);
if ParentForm <> nil then begin
fSavedWndProc := ParentForm.WindowProc;
ParentForm.WindowProc := ParentWindowProc;
end;
end;
procedure TFrame2.DestroyWnd;
var
ParentForm: TCustomForm;
begin
ParentForm := GetParentForm(Self);
if ParentForm <> nil then
ParentForm.WindowProc := fSavedWndProc;
inherited;
end;
procedure TFrame2.DoEnterSizeMove;
begin
if Assigned(fOnEnterSizeMove) then
fOnEnterSizeMove(Self);
end;
procedure TFrame2.DoExitSizeMove;
begin
if Assigned(fOnExitSizeMove) then
fOnExitSizeMove(Self);
end;
procedure TFrame2.ParentWindowProc(var AMessage: TMessage);
begin
fSavedWndProc(AMessage);
if AMessage.Msg = WM_ENTERSIZEMOVE then
DoEnterSizeMove;
if AMessage.Msg = WM_EXITSIZEMOVE then
DoExitSizeMove;
end;
Note that the messages are sent whenever a secondary message loop for moving / sizing has been started or left - there is no way to distinguish between moving and sizing. If you need to make sure that you catch sizing only, you should compare old and new size of the frame in the handler.
You could try the following Implementation.
-Hook owner form's on Resize event, handle it within your frame, and Fire any Event Handler the parent OnResize Might have had.
type
TFrame2 = class(TFrame)
Label1: TLabel;
procedure FrameClick(Sender: TObject);
private
{ Private declarations }
FOnResize: TNotifyEvent;
procedure OnFrameResize(Sender: TObject);
public
{ Public declarations }
// custom Frame constructor
constructor Create(AOwner: TComponent); override;
end;
implementation
{$R *.dfm}
{ TFrame2 }
constructor TFrame2.Create(AOwner: TComponent);
begin
inherited;
FOnResize := TForm(AOwner).OnResize;
TForm(AOwner).OnResize := OnFrameResize;
end;
procedure TFrame2.OnFrameResize(Sender: TObject);
begin
Label1.Caption := 'resize fired';
if @FOnResize <> nil then
FOnResize(Parent);
end;
I think the it could be done by the resizing event stopping (to reset time) and starting a timer with et short timeout (lik 0,3 secs). Then the resize of the fram will be done shortly after the rest of the resizing.
1) Mark your frame with special interface smth. like: INeedLayoutAfterResize :)
2) Write custom descendant of TForm that would capture resize events (as shown in earlier answers), than looks for its children and if some child marked, than re-layout its content.
actually I use such approach for save and restore controls state. my custom from iterate over its children controls and look for Tag property if it is less then zero, write its state to ini-file.