Component placement with align properties at runtime

I am saving and then re-loading form data from json at runtime. I have a question regarding the placement of aligned components as follows.

Example: A panel with a child TPanel aligned alTop, a TSplitter aligned alTop and then another panel aligned alTop.

After you’ve saved the controls of the parent panel from the TPanel.Controls order, and then reload in the same order, there is no certainty that the designed order will be preserved.

I suspect that the order that the sizing properties are assigned (possibly left, top, width, height, align from a dfm file) is a clue but I thought I’d ask if any other considerations or techniques are required.

Their is many questions about what you have made relating to your object design
That I can only begin to guess sorry
Are you hiding your object data under TCustomMyPanel first???
Is just the beginning
are you overriding Size, Mouse move parts of the object

In my experience, with the alignment settings you have indicated here, the IDE will have problems redisplaying the form as designed. Is this your experience now?

Is there a reason why the second panel is not aligned alClient, to fill the remainder of the panel’s area?

so may questions of your code
have you enforced the settings with a repaint or excited with an invalidate
so many questions

Lex, please stop commenting when you do not know what you’re talking about. It’s not helpful. I appreciate you trying to help but only do so when you’re certain of your answer. What you wrote there shows you don’t have a clue what is being discussed.

I agree with Aaron, this is a problematic arrangement. You should have one of the controls set to alClient - I realize the RTL could handle this better but it doesn’t. :frowning:

Their is noting to see to the comment as he wants to show something
he needs a page on this subject at his level and I have not fund it

At this point i think I’ve solved this problem as follows.

I am setting all properties from Rtti.
It is critical that related properties are set in the correct order. In this case the position/ size properties below must be applied in the order as shown. In makes sense now because by the time the align property is set it must know where it is now and align accordingly.
left | top | width | height | align

If you apply the properties in a different order (width | top | left | align |height) then the component placement may be incorrect.

I’ve also noticed in other cases that it is problematic if the setting of properties using Rtti is in the wrong order. Example: TComboBox> attempting to set ItemIndex before Lines.Text will only set ItemIndex to -1 no matter what value you pass.

I will report at a later date whether this is the entire solution or not after we have done extended system wide testing.

Thanks for all assistance.
Gerard Hook

Hi @Gerard_Hook ,

Instead of using RTTI to reload form data/settings, perhaps you could use the builtin delphi stream interface to loading/saving forms. This should mean that it behaves the same way as you expect delphi to work.

Have a look at

https://www.scalabium.com/faq/dct0065.htm

and

I thought I’d close this topic by sharing a solution to a problem that took me too long to figure so it may save someone else some time.

Problem>
Child components of a parent are indexed by the order in which they are created.
In the case of TFlowPanel, if you move the position of a controls position at runtime [TFlowPanel.SetControlIndex(ACtrl, APos + 1)], the original creation order index does not change. Given that the ControlIndex value of a control in a TFlowPanel is not persistent, saving and then reloading the controls to the flowpanel will not reflect the new moved controls position. Hmmm!

Solution (simpler than I 1st thought)>
Record all controls to a list recording the control position value.
Remove all controls from the TFlowPanel by setting parent to nil.
Reorder the list as required.
Reinstate the controls to the TFlowPanel in the correct order.
See below.

procedure TForm12.Button7Click(Sender: TObject);
var
  AList: IList<TControl>;
  i: integer;
  ACtrl: TControl;
  APos: integer;
begin
  Memo1.Lines.Clear;
  pnlFrame.LockDrawing;
  try
    AList := TCollections.CreateList<TControl>;
    // Load the control list recording the ControlIndex
    for i := 0 to pnlFrame.ControlCount - 1 do
    begin
      ACtrl := pnlFrame.Controls[i];
      APos := pnlFrame.GetControlIndex(ACtrl);
      ACtrl.Tag := APos;
      AList.Add(ACtrl);
    end;
    // Sort the control list by the ControlIndex
    AList.Sort(TComparer<TControl>.Construct(
      function(const L, R: TControl): integer
      begin
        Result := CompareValue(L.Tag, R.Tag);
      end));
    // Remove the controls from the parent panel
    for ACtrl in AList do
      ACtrl.Parent := nil;
    // Re-instate the controls to the panel
    for ACtrl in AList do
      ACtrl.Parent := pnlFrame;
  finally
    pnlFrame.UnlockDrawing;
  end;
end;

Gerard Hook