Tracciare il codice per vedere cosa succede, ho trovato la regolazione seguente.
procedure TForm1.WMWindowPosChanging(var Message: TWMWindowPosChanging);
var
MessageWidth: Integer;
begin
MessageWidth := Message.WindowPos.cx;
inherited;
if MessageWidth > Message.WindowPos.cx then
GroupBox1.Width := GroupBox1.Width - MessageWidth + Message.WindowPos.cx;
end;
Questa non è una soluzione generalizzata, ma chiarisce qual è il problema. VCL richiede una dimensione della finestra per il suo modulo che non è concessa dal sistema operativo poiché è più grande del desktop. Da quel momento in poi, il modulo riprende l'ancoraggio del controllo figlio con la larghezza specificata per il tempo di progettazione, che è maggiore della larghezza del modulo del client, quindi il lato destro del controllo figlio supera i limiti.
Un'altra soluzione può essere quella di ignorare la gestione del messaggio WM_GETMINMAXINFO
per consentire al sistema operativo di concedere la larghezza richiesta.
procedure TForm1.WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);
begin
inherited;
Message.MinMaxInfo.ptMaxTrackSize.X := 1200;
end;
questo non può essere una buona soluzione perché allora la forma sarà più grande del desktop.
Per quanto riguarda gli elementi "a" e "b", non penso che sia possibile "b" - o almeno non è possibile effettuare il relayout VCL da solo - poiché VCL rimanda le regole di ancoraggio fino a dopo il componente (modulo) è stato caricato. A quel punto, la larghezza del modulo è diversa dalla larghezza del tempo di progettazione ma il posizionamento dei controlli secondari rimane inalterato. Nessuna quantità di forzatura al layout li renderà nuovamente sincronizzati.
Tuttavia dovrebbe essere possibile ricalcolare tutto da zero se il proprio codice mantiene un riferimento alla larghezza del tempo di progettazione. Sotto non è completo il codice.
type
TForm1 = class(TForm)
..
private
FAdjustShrinkWidth, FAdjustShrinkHeight: Integer;
protected
procedure Loaded; override;
public
procedure SetBounds(ALeft: Integer; ATop: Integer; AWidth: Integer;
AHeight: Integer); override;
end;
...
procedure TForm1.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
var
TrackWidth, TrackHeight: Boolean;
begin
TrackWidth := AWidth = 1200;
TrackHeight := AHeight = ??;
inherited;
if TrackWidth and (Width < AWidth) then
FAdjustShrinkWidth := AWidth - Width;
if TrackHeight and (Height < AHeight) then
FAdjustShrinkHeight := AHeight - Height;
end;
procedure TForm1.Loaded;
procedure ReadjustControlAnchors(Control: TWinControl);
var
i: Integer;
begin
for i := 0 to Control.ControlCount - 1 do
if (akRight in Control.Controls[i].Anchors) or (akBottom in Control.Controls[i].Anchors) then begin
Control.Controls[i].Left := // some complex calculation depending on the anchors set;
Control.Controls[i].Top := // same as above;
Control.Controls[i].Width := // same as above;
Control.Controls[i].Height := // same as above;
if (Control.Controls[i] is TWinControl) and (TWinControl(Control.Controls[i]).ControlCount > 0) then
ReadjustControlAnchors(TWinControl(Control.Controls[i]));
end;
end;
begin
inherited;
ReadjustControlAnchors(Self);
end;
Non ho idea di come riempire gli spazi vuoti nel codice sopra. Leggere e tracciare il codice VCL può essere obbligatorio per imitare l'ancoraggio VCL.
Non riesco a pensare a nulla per 'a'.
Aggiornamento:
VCL ha effettivamente lasciato una backdoor per un controllo di mentire ai suoi figli immediate relative alla dimensione del loro genitore mentre stanno ancorando. Documentation spiega un po 'diverso:
UpdateControlOriginalParentSize è un metodo protetto che aggiorna le dimensioni originali del controllo padre. Viene utilizzato internamente per aggiornare le regole di ancoraggio del controllo.
Possiamo usarlo per indicare al gruppo le dimensioni originali desiderate.
type
TForm1 = class(TForm)
..
private
FWidthChange, FHeightChange: Integer;
protected
procedure UpdateControlOriginalParentSize(AControl: TControl;
var AOriginalParentSize: TPoint); override;
public
procedure SetBounds(ALeft: Integer; ATop: Integer; AWidth: Integer;
AHeight: Integer); override;
end;
...
procedure TForm1.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
var
RequestedWidth, RequestedHeight: Integer;
begin
RequestedWidth := AWidth;
RequestedHeight := AHeight;
inherited;
if csLoading in ComponentState then begin
if RequestedWidth <> Width then
FWidthChange := Width - AWidth;
if RequestedHeight <> Height then
FHeightChange := Height - AHeight;
end;
end;
procedure TForm1.UpdateControlOriginalParentSize(AControl: TControl;
var AOriginalParentSize: TPoint);
begin
inherited;
if akRight in AControl.Anchors then
AOriginalParentSize.X := AOriginalParentSize.X - FWidthChange;
if akBottom in AControl.Anchors then
AOriginalParentSize.Y := AOriginalParentSize.Y - FHeightChange;
end;
Rilevo ancora una volta che questo avrà effetto solo figli diretti del modulo. Se la groupbox ospita controlli che si ancorano a destra e in basso, deve anche eseguire l'override dello stesso metodo.
Si noti inoltre che ciò non annulla il fatto che la larghezza del modulo è stata modificata. Questo è se ci fosse un controllo ancorato a sinistra che è all'estrema destra del modulo, non si sostituirà al limite del client. Agirà come se la larghezza della forma fosse diminuita, cioè rimarrebbe fuori dalla vista.
Che ne dici di impostare la proprietà 'Align' di GroupBox su' alTop'? Ciò equivale a abilitare le ancore sinistra, superiore e destra in modo che si allunghi mentre il modulo padre viene ridimensionato. –
Ho osservato una situazione simile con una cornice in una forma. Se il frame è più grande del modulo, non viene ridimensionato alle dimensioni del modulo anche se la proprietà Align è impostata su Client. Con la cornice il trucco è rendere più piccolo e lasciare che la proprietà del Client faccia il lavoro. –