AutoSize and AutoWrap conflict in TFlowPanel

I am trying to use the TFlowPanel component as follows:

  • Place in the main form Form1 of the FlowPanel1: TFlowPanel component FlowPanel1: TFlowPanel .
  • Set Form1.Width = 400 , FlowPanel1.Align = alTop , FlowPanel1.AutoSize = True , FlowPanel1.AutoWrap = True .
  • Place the FlowPanel1 5 SpeedButtons on the button and set their Width to 64.
  • Compile and run.
  • Reduce the width of the form (something about Form1.Width = 200 ).

For some reason, the speed buttons do not automatically line up in two lines when the user resizes the form. Despite this, they line up in two lines when AutoSize = False , AutoWrap = True .
What is the reason for this behavior and how to solve it?

Change I found a "quick and dirty" solution. The following code is the TFlowPanel.OnResize event TFlowPanel.OnResize :

 procedure TForm1.FlowPanel1Resize(Sender: TObject); begin with FlowPanel1 do begin AutoSize := False; Realign; // line up controls AutoSize := True; // adjust TFlowPanel.Height end; end; 

However, I'm still wondering if there is a standard way to solve the problem.

+4
source share
2 answers

I could not find the exact reason for this behavior in the code, but basically you challenged two calibration options, AutoSize and Align . The problem is that when you resize the form, the AutoSize control is set to True and Align set to alTop will first try to automate the controls and then align to the top of its parent. What I can say for sure, these two properties should not be combined, at least with their logical meaning.

What I suggest to your workaround is to turn off autorun by default, and in OnResize event, turn it on temporarily and return to off to automatically adjust the height. Therefore, in the code, it would change simply like this:

 procedure TForm1.FlowPanel1Resize(Sender: TObject); begin // there no Realign here, since the AlignControls request is called // at control resize, so here you have children already aligned, what // you then need is to request the control to autosize the height and // turn off the autosizing to the default, disabled state FlowPanel1.AutoSize := True; FlowPanel1.AutoSize := False; end; 
+4
source

tl, dr: This is a bug in TFlowPanel .

Usually, AutoSize and Align properties combine very well by default, as this is taken care of already at the TControl level, so I wondered why this happened. I noticed the override TFlowPanel method in AlignControls and decided to bypass it for testing purposes:

 type TWinControlAccess = class(TWinControl); TAlignControls = procedure(Instance: TObject; AControl: TControl; var Rect: TRect); TFlowPanel = class(Vcl.ExtCtrls.TFlowPanel) protected procedure AlignControls(AControl: TControl; var Rect: TRect); override; end; TForm1 = class(TForm) ... procedure TFlowPanel.AlignControls(AControl: TControl; var Rect: TRect); begin // Skip TCustomFlowPanel.AlignControls TAlignControls(@TWinControlAccess.AlignControls)(Self, AControl, Rect); end; procedure TForm1.FlowPanel1Resize(Sender: TObject); begin // Do my own aligning of the last button if FlowPanel1.ClientWidth < Button5.BoundsRect.Right then begin Button5.Left := 1; Button5.Top := Button1.Height + 1; end else if FlowPanel1.ClientWidth > Button4.BoundsRect.Right + Button5.Width then begin Button5.Left := Button4.BoundsRect.Right; Button5.Top := 1; end; end; 

Now it works as expected. So what happened to the TFlowPanel implementation of AlignControls ? It looks like this:

 if AutoSize then Rect := TRect.Create( Rect.Left, Rect.Top, Rect.Left + (ExplicitWidth - (Width - (Rect.Right - Rect.Left))), Rect.Top + (ExplicitHeight - (Height - (Rect.Bottom - Rect.Top)))); 

When this part is commented out, the behavior is the same as with Align , and also not. Now I would like to introduce this to the CC, but perhaps I do not notice some of its aspects. Please edit or comment on when (and then why) this code is really necessary.

+4
source

Source: https://habr.com/ru/post/1433701/


All Articles