Конференция "Компоненты" » неполучается сохранить поле TComponent в TCollectionItem [D7, WinXP]
 
  • AlexRayne (04.09.09 16:07) [0]
    пытаюсь создать коллекцию разнородных компонентов.
    для етого создаю контейнер TCollectionItem в котором помещаю published свойство моего компонента ( published  property Filter : BaseEventFilter).
    саму коллекцию вкладываю в компонент - FiltersSet

    при добавлении нового фильтра создаю его с владельцем FiltersSet который содержит коллекцию
    (
    function  LogTracks.Add(const template : LogTrackContainer): LogTrackContainer;
    begin
     result := add(template.Name, template.Filter.CreateInstance(FiltersSet(Owner)), template.TuneForm);
    end;
    )
    а как еще? TCollectionItem неможет же быть владельцем TComponent.

    на реальном примере использую далекого потомка AdressFilter от базового класса BaseEventFilter

    охраняется все кроме того что надо.
    как быть?
  • AlexRayne (04.09.09 16:12) [1]
    собсно часть исходника

    type
       LogTrackContainer = class(TCollectionItem)
         public
           FName   : string;
           TuneForm : TFrame;
           FFilter : BaseEventFilter;
           //constructor Create(Collection: TCollection); override;
           destructor Destroy;override;
           procedure SetDisplayName(const Value: string); override;
           function  GetDisplayName: string; override;
         protected
           function GetFilterClass : string;
           procedure InitFilterClass(const value : string);
           procedure SetFilter(value : BaseEventFilter);
         published
           property Name : string read FName write FName;
           //property FilterClass : string read GetFilterClass write InitFilterClass;
         published
           property Filter : BaseEventFilter read Ffilter write SetFilter;
       end;

       LogTracks = class(TOwnedCollection)
         private
           function  GetItem(Index: Integer): LogTrackContainer;
           procedure  SetItem(Index: Integer; value : LogTrackContainer);
         public
           function  Add(const aName : string; aFilter : BaseEventFilter; aTuneForm : TFrame): LogTrackContainer;overload;
           function  Add(const template : LogTrackContainer): LogTrackContainer;overload;

           function  IndexOf(const aName: string): integer;overload;
           function  Find(const aName: string): LogTrackContainer;overload;
           function  IndexOf(value : TClass): integer;overload;
           function  Find(value : TClass): LogTrackContainer;overload;
           function  IndexOf(value : LogTrackContainer): integer; overload;

           function  Insert(Index: Integer): LogTrackContainer;
           property  Items[Index: Integer]: LogTrackContainer read GetItem write SetItem; default;

           procedure GatterItemsNames(Target : TStrings);
         end;

       FiltersSet = class(TComponent)
           FItems : LogTracks;
           procedure AssignItems(value : LogTracks);
           constructor Create(aOwner : TComponent);override;
           destructor Destroy;override;
         published
           property Items : LogTracks read FItems write AssignItems;

       end;

    var
       LogFiltersEnum : LogTracks;

    procedure Register;

    implementation
    uses AdressPaleteFrame
       , sysutils
         ;

    {******************************************************************************
                           LogTracks
    *******************************************************************************}
    function  LogTracks.GetItem(Index: Integer): LogTrackContainer;
    begin
     result := LogTrackContainer(inherited GetItem(Index));
    end;

    procedure  LogTracks.SetItem(Index: Integer; value : LogTrackContainer);
    begin
     inherited SetItem(Index, value);
    end;

    function  LogTracks.Insert(Index: Integer): LogTrackContainer;
    begin
     result := LogTrackContainer(inherited Insert(Index));
    end;

    function  LogTracks.Add(const aName : string; aFilter : BaseEventFilter; aTuneForm : TFrame): LogTrackContainer;
    begin
       result := LogTrackContainer(Add());
       result.Filter := aFilter{.CreateInstance};
       result.TuneForm := aTuneForm;
       result.DisplayName := aName;
    end;

    function  LogTracks.Add(const template : LogTrackContainer): LogTrackContainer;
    begin
     result := add(template.Name, template.Filter.CreateInstance(FiltersSet(Owner)), template.TuneForm);
    end;

    .............
    ............
    ..............

    {******************************************************************************
                           LogTrackContainer
    *******************************************************************************}
    procedure LogTrackContainer.SetDisplayName(const Value: string);
    begin
     Name := Value;
    end;

    function  LogTrackContainer.GetDisplayName: string;
    begin
     result := Name;
    end;

    destructor LogTrackContainer.Destroy;
    begin
       FreeAndNil(FFilter);
       inherited;
    end;

    function LogTrackContainer.GetFilterClass : string;
    var
     def : LogTrackContainer;
    begin
       def := LogFiltersEnum.Find(Filter.ClassType);
       if assigned(def) then
           result := def.Name
       else
           result := '?';
    end;

    procedure LogTrackContainer.InitFilterClass(const value : string);
    var
     def : LogTrackContainer;
    begin
       def := LogFiltersEnum.Find(value);
       if assigned(def) then begin
              FreeAndNil(FFilter);
              TuneForm := nil;
           if (not assigned(Filter)) then begin
               FFilter := def.Filter.CreateInstance(FiltersSet(collection.Owner));
               TuneForm := def.TuneForm;
           end;
       end;
    end;

    procedure LogTrackContainer.SetFilter(value : BaseEventFilter);
    begin
     FFilter := value;
     //FFilter.FreeNotification(Collection.Owner as TComponent);
    end;
    {****************************************************************************
                                 FiltersSet
    ******************************************************************************}
    constructor FiltersSet.Create(aOwner : TComponent);
    begin
     inherited;
     FItems := LogTracks.Create(Self, LogTrackContainer);
    end;

    destructor FiltersSet.Destroy;
    begin
     FreeAndNil(FItems);
     inherited;
    end;

    procedure FiltersSet.AssignItems(value : LogTracks);
    begin
     Fitems.Clear;
     Fitems.Assign(value);
    end;

    procedure Register;
    begin
     RegisterClasses([FiltersSet,LogTracks,LogTrackContainer,AdressFilter]);
    end;

    initialization begin
       LogFiltersEnum := LogTracks.Create(nil, LogTrackContainer);
       LogFiltersEnum.Add('AdressFilter', AdressFilter.Create(nil), EditAdressPaleteFrame);
    end;

    finalization begin
       FreeAndNil(LogFiltersEnum);
    end;

    end.
  • Сергей М. © (04.09.09 16:46) [2]
  • AlexRayne (04.09.09 16:47) [3]
    если BaseEventFilter унаследовать от TPersistent а не TComponent, то начнуть сохраняться его свойства, но сам он создаваться небудет
  • Сергей М. © (04.09.09 16:58) [4]
    Для сериализации любых не опубликованных свойств существуют методы TPersistent.DefineProperties и TFiler.DefineProperty
  • AlexRayne (04.09.09 17:26) [5]
    Сергей, спасибо за статью. но надежд она мне больших непридала. такое ощущение что чтобы работало надо переписать GetChildren для класса-хозяина-коллекции, и еще приделать fixup свой ко всему етому.
    оно конешно глобально, и наверно даже полезно, и наверно уже кемто сделано.
    если у Вас есть чтото похожее киньте сцылко.

    а пока я пробую чегото попроще сделать - сохраняю тип фильтра в свойстве, а при загрузке TCollectionItem по етому свойству конструирует мой компонент., если он загружается самый первый, то все его свойства затем загружаются вдогонку.
  • AlexRayne (05.09.09 00:49) [6]
    пришел к тому что отказался от колекции вообще, и стал использовать собственный список компонента-коллекции для хранения многихTComponent .
    все получилось намного проще.
    тока вот теперь немогу заставить отображаться в object tree view субкомпоненты
    как ето сделать?

    вот текст нового компонента

    type

       FiltersSet = class(TComponent)
         protected
           //FItems : LogTracks;
           procedure GetChildren(Proc: TGetChildProc; Root: TComponent);override;
           function GetChildOwner: TComponent; override;
           function GetItem(index : integer) : baseEventFilter;
         public
           function  Add(const aName : string; template : BaseEventFilter) : integer;overload;
           function  Add(const aName : string; aFilterClass : EventFilterClass) : integer;overload;
           procedure GatterItemsNames(target : TStrings);

           constructor Create(aOwner : TComponent);override;
           destructor Destroy;override;
           property Items[Index : integer] : BaseEventFilter read GetItem;
       end;

    var
       LogFiltersEnum : FiltersSet;

    procedure Register;

    implementation
    uses AdressPaleteFrame
       , sysutils
         ;

    {****************************************************************************
                                 FiltersSet
    ******************************************************************************}
    constructor FiltersSet.Create(aOwner : TComponent);
    begin
     inherited;
    end;

    destructor FiltersSet.Destroy;
    begin
     inherited;
    end;

    procedure FiltersSet.GetChildren(Proc: TGetChildProc; Root: TComponent);
    var
     I: Integer;
     OwnedComponent: TComponent;
    begin
       for I := 0 to ComponentCount - 1 do
       begin
         OwnedComponent := Components[I];
         if not OwnedComponent.HasParent then Proc(OwnedComponent);
       end;
    end;

    function FiltersSet.GetChildOwner: TComponent;
    begin
     result := self;
    end;

    function FiltersSet.GetItem(index : integer) : BaseEventFilter;
    begin
     result := components[index] as BaseEventFilter;
    end;

    function  FiltersSet.Add(const aName : string; aFilterClass : EventFilterClass) : integer;
    var
     aFilter : baseEventFilter;
    begin
       afilter := aFilterClass.Create(Self);
       aFilter.Name := aName;
       afilter.SetSubComponent(true);
       result := afilter.ComponentIndex;
    end;

    function  FiltersSet.Add(const aName : string; template : BaseEventFilter) : integer;
    var
     aFilter : baseEventFilter;
     idx : integer;
     newname : string;
     namecomp : tcomponent;
    begin
       newname := aName;
       namecomp := FindComponent(aName);
       if assigned(namecomp) then
           idx := namecomp.ComponentIndex
       else
           idx := -1;
       while idx >= 0 do begin
         newname := aName + IntTostr(idx+1);
         namecomp := FindComponent(newName);
         if assigned(namecomp) then
           idx := namecomp.ComponentIndex
         else
           idx := -1;
       end;
       afilter := template.CreateInstance(Self);
       aFilter.Name := newName;
       afilter.SetSubComponent(true);
       result := afilter.ComponentIndex;
    end;

    procedure FiltersSet.GatterItemsNames(target : TStrings);
    var
     idx : integer;
    begin
     for idx := 0 to ComponentCount -1 do
       target.add(components[idx].name);
    end;

    procedure Register;
    begin
     RegisterClasses([FiltersSet,AdressFilter]);
    end;

    initialization begin
       LogFiltersEnum := FiltersSet.Create(nil);
       LogFiltersEnum.Add('AdressFilter', AdressFilter);
    end;

    finalization begin
       FreeAndNil(LogFiltersEnum);
    end;

    end.
  • DimaBr © (07.09.09 09:01) [7]
    Для того чтобы они отображались в Object Tree View компоненты должны лежать на форме или смотрите в сторону Sprig
  • alexrayne (02.10.09 11:25) [8]
    с етим контейнером вылезла новая трабла - если я создаю inherited форму\фрейм подкомпоненты контейнера немогут найти своих предков при сохранении\загрузке, по той причине что поиск идет по имени компонента в корневой форме а не в контейнере.

    подскажите как лечица.

    может это вообще ошибка использовать контейнер как собственник своих компонентов? может надо пойти другим путем?
  • alexrayne (02.10.09 11:30) [9]
    может имеет смысл перебазировать свои классы с компонентов на контролы? контрол имеет раздельных owner и parent.
  • alexrayne (02.10.09 14:06) [10]
    уря!. лечение оказалось простым как 2капли:

    @@ -52,6 +52,7 @@
    constructor FiltersSet.Create(aOwner : TComponent);
    begin
      inherited;
    +  SetInline(true);
    end;

    destructor FiltersSet.Destroy;
 
Конференция "Компоненты" » неполучается сохранить поле TComponent в TCollectionItem [D7, WinXP]
Есть новые Нет новых   [134466   +3][b:0][p:0.001]