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?
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.
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.
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.
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;