Сохранение/загрузка вложенных компонент в dfm

Есть компонент сParentComponent (наследник TWinControl) который хранит ссылку на список вложеных компонентов (наследники TComponent). Метод GetChildren переопределен
procedure сParentComponent.GetChildren(Proc: TGetChildProc;Root: TComponent);
begin
 for i := 0 to SubComponents.Count-1 do
 begin
 Proc(TComponent(subcomponents.Items[i]));
 end;
end;
таким образом, список компонентов сохраняется в dfm, но!!! 2 раза. Первый - как вложенные компоненты у сParentComponent, второй - на уровне компонентов формы. Как оставить сохранение компонентов только у сParentComponent. Как потом при загрузке собрать эти вложенные компоненты обратно в список subcomponents (TList) у cParentControl. Owner-ом субкомпонетов является форма.
5 ответов

Про назначение кнопки "Правка" не догадываетесь? Значит - ни читали правила раздела, значит - нарываетесь на штраф...


Тот кусок кода, который вы привели, никак не поможет пониманию сути вашего вопроса. Покажите, как вы создаете наследника.


Тот кусок кода, который вы привели, никак не поможет пониманию сути вашего вопроса. Покажите, как вы создаете наследника.
То, что не поможет я догадывался. просто не знаю какую часть кода выложить. чтоб помогло... у редактора компонента cParentComponent переопределен метод Edit, по вызову которого создается форма. На форме имеется кнопка, которая позволяет добавлять субкомпоненты. Код нажатия на кнопку такой:
procedure TObjExplorerDlg.AddObjBtnClick(Sender: TObject);
var obj:cSubComponent;
begin
 obj:=nil;
 if Assigned(Designer) then
 begin
 obj:=cSubComponent(Designer.CreateComponent(cSubComponent, ParentComponent , -1, -1, -1, -1));
 <i> // basegl.InsertComponent(obj); // Если раскоментарить, то сохраняется правильно(1 раз и как
 //субкомпонент), но не знаю как потом загрузить правильно. Кроме того при таком создании
 //компонент не отображается в списке Structures (утилита среды Delphi).</i>
 basegl.subcomponents.Add(obj); <i>// добавление созданного компонента в список вложеных компонент</i>
 Designer.Modified;
 end;
end;


Выкладываю пример созданный alexBlack-ом (за что ему огромное спасибо). с незначительными доработками. В данном примере создается ParentComponent, на котором размещаются два контрола. Иерархия компонентов правильно отображается в IDE-ом structure и правильно сохраняется в форму. Для активации примера необходимо проинсталировать компонент, кинуть на форму Tbutton и два раза по нему кликнуть
unit TestUnit;

interface

uses Classes, Controls, ExtCtrls, StdCtrls, DesignIntf, DesignEditors,
 ToolsAPI, Dialogs, ****************;

type
 TParentComponent = class(twincontrol)
 private
 FList : TList;
 protected
 procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
 public
 constructor Create(AOwner:TComponent); override;
 end;

 TSubComponent = class(TLabel) <font color="red">// Если унаследовать от чистого Tcontrol то компоненты не правильно отобразятся в Structures</font>
 end;

 TButtonEditor = class(TComponentEditor)
 procedure Edit; override;
 end;

procedure Register;

<b>implementation</b>

<b>procedure</b> Register;
<b>begin</b>
 RegisterComponentEditor(TButton, TButtonEditor);
 RegisterComponents('Samples', [TParentComponent, TSubComponent]);
<b>end</b>;

<b>constructor</b> TParentComponent.Create(AOwner:TComponent);
<b>begin</b>
 inherited Create(AOwner);
 FList := TList.Create;
<b>end</b>;

<b>procedure</b> TButtonEditor.Edit;
var P:TParentComponent;
 obj:tsubcomponent;
<b>begin</b>
 if Designer = nil then exit;
 P := Designer.CreateComponent(TParentComponent, Designer.Root, 10, 10, 10, 10) as TParentComponent;
 obj:=tsubcomponent(Designer.CreateComponent(TSubComponent, P, 10, 10, 10, 10));
 obj.Parent:=p;<font color="red">//Если закоментарить работать не будет</font>
 P.flist.add(obj);
 obj:=tsubcomponent(Designer.CreateComponent(TSubComponent, P, 10, 10, 10, 10));
 obj.Parent:=p;<font color="red">//Если закоментарить работать не будет</font>
 P.flist.add(obj);
<b>end;</b>

<b>procedure</b> TParentComponent.GetChildren(Proc: TGetChildProc; Root: TComponent);
var I: Integer;
 Control: TSubComponent;
<b>begin</b>
 for I := 0 to FList.Count - 1 do
 begin
 Control := TSubcomponent(FList[i]);
 if Control.Owner = Root then
 Proc(Control);
 end;
<b>end;</b>
<b>end.</b>
Однако лично у меня не совсем этот случай . Дело в том, что мои SubComponent-ы не визуальные, следовательно не Tcontrol, а TComponent. А следовательно не имеют свойства parent. В коде отмечено две строки в которых это свойство используется. При закоментаривании этих строк форма перестает правильно сохраняться, субкомпоненты сохраняются дважды (суть проблемы в первом посте). Вопрос остается - как побороть сохранение компонента на уровне формы
object form1: TForm
 object ParentComponent1: TParentComponent
 object SubComponent1: TsubComponent
 end
 end
 <font color="red">Object SubComponent1: TsubComponent
 end</font>
end
Цветом отмечено лишнее


Итак решение найдено. У TComponent есть два динамических метода, которые по умолчанию всегда возвращают одно и тоже. HasParent - возвращает false, GetParentComponent - возвращает nil. Перекрывая эти методы, и вернув true в HasParent и вернув ссылку на ParentComponent в GetParentComponent все будет удачно сохраняться в dfm файл и будет правильно отображаться в structure окошке.