Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

ПодСвойство компонента


DimaBr ©   (2005-11-28 11:54:00) 

Здравствуйте !
Компонент имеет свойство типа

ThbStoredProc = class(TPersistent)
 private
   fStoredProcUpdate: TStoredProc;
   procedure SetStoredProcUpdate(const Value: TStoredProc);
 public
   constructor Create(AOwner: TComponent);
   destructor Destroy;override;
   procedure AssignTo(Source: TPersistent);override;
 published
   property StoredProcUpdate: TStoredProc read fStoredProcUpdate write SetStoredProcUpdate;
end;

...

constructor ThbStoredProc.Create(AOwner: TComponent);
begin
 fStoredProcUpdate := TStoredProc.Create(AOwner);
 fStoredProcUpdate.SetSubComponent(true);
 ...
end;

То есть свойство сомпонента состоит из StoredProc и других подсвойств. При выборе процедуры и присвоении параметров
в DFM-ке видим

StoredProc.StoredProcUpdate.DatabaseName = 'SalaryODBC'
StoredProc.StoredProcUpdate.StoredProcName = 'EmployeeUpdate;1'
StoredProc.StoredProcUpdate.ParamData = <
     item
       StoredProc.StoredProcUpdate.DataType = ftInteger
       StoredProc.StoredProcUpdate.Name = '@RETURN_VALUE'
       StoredProc.StoredProcUpdate.ParamType = ptResult
     end
     item
       StoredProc.StoredProcUpdate.DataType = ftString
       StoredProc.StoredProcUpdate.Name = '@NameLeftEmployee'
       StoredProc.StoredProcUpdate.ParamType = ptInput
     end>

Но при чтении из ресурса возникает ошибка:
"Error reading
TParam StoredProc.StoredProcUpdate.DataType: Property StoredProc does not exists."

Получается что подсвойство создаётся раньше свойства, что ли ? Как с этим бороться ?


Макс Черных   (2005-12-03 21:33:00) [1]

2 jack128.

Ладно, насчет чудес со стримингом в Delphi убедил.
Проблема описана и в Quality Central, рекомендую почитать:
http://qc.borland.com/wc/qcmain.aspx?d=11126

Тем не менее, Assign все равно надо писать правильно.


> надо срочно кондиционер чинить, то скоро у меня все работники
> перегреются :)
> я не против ;)


Говорят, что он (кондер) совсем мертвый, чинить невыгодно. Менять будем на кокой нибудь путевый.


jack128   (2005-12-03 20:22:00) [2]

Да. Но это все теория. С практической точки зрения я бы просто отказался от класса ThbStoredProc, а сделал бы наследника TStoredProc и перенёс бы весь функционал в него.


jack128   (2005-12-03 20:01:00) [3]

Макс Черных ©   (03.12.05 19:17) [14]
И куда по твоему должно присваиваться то, что написано между item и end ?  

Ну присваиваться то ему некуда, но это не из-за глюка в Assign(To).  Я же не просто так говорю, я сейчас тестовый пример накатал, пакет сделал. В конце концов можно просто убрать метод Assign , от этого ничего не измениться.

Тут нужно долго и упорно сидеть под дебагером и смотреть механизм стриминга дельфи. Мне этим лень заниматься, но кое какие соображения есть. Есть достаточно известный компонент VirtualTree, там у человека возникла похожая(ИМХО один в один) проблема.  
Итак есть компонент TbaseVirtualTree, у него есть свойство VTHeader - наследник TPersistent. У этого свойства есть подсвойство - коллекция Columns. Как видешь от сабжевого варинта отличает отсутствием промежуточного компонента TStoredProc.
И вот как Майк(автор компонента) изваращается и вот что он пишет по этому поводу(ключевые моменты я выделил):

type
 // --- HACK WARNING!
 // This type cast is a partial rewrite of the private section of TWriter. The purpose is to have access to
 // the FPropPath member, which is otherwise not accessible. The reason why this access is needed is that
 // with nested components this member contains unneeded property path information(то что мы видем). These information prevent
 // successful load of the stored properties later.
 // In Classes.pas you can see that FPropPath is reset several times to '' to prevent this case for certain properies.
 // Unfortunately, there is no clean way for us here to do the same.
 {$hints off}
 TWriterHack = class(TFiler)
 private
   FRootAncestor: TComponent;
   FPropPath: string;
 end;
 {$hints on}

procedure TVTHeader.WriteColumns(Writer: TWriter);

// Write out the columns but take care for the case VT is a nested component.

var
 LastPropPath: String;
 
begin
 // Save last property path for restoration.
 LastPropPath := TWriterHack(Writer).FPropPath;
 try
   // If VT is a nested component then(вспоминаем, что StoredProp у нас как nested component) this path contains the name of the parent component at this time
   // (otherwise it is already empty). This path is then combined with the property name under which the tree
   // is defined in the parent component. Unfortunately, the load code in Classes.pas does not consider this case
   // is then unable to load this property.
   TWriterHack(Writer).FPropPath := '';
   Writer.WriteCollection(Columns);
 finally
   TWriterHack(Writer).FPropPath := LastPropPath;
 end;
end;

Макс Черных ©   (03.12.05 19:17) [14]
надо срочно кондиционер чинить, то скоро у меня все работники перегреются :)

я не против ;)


Макс Черных   (2005-12-03 19:17:00) [4]


> fStoredProc изначально равен nil,
> это не так, он создается в конструкторе THandBook.


Ну тут я согласен, имелось в виду, что он не проинициализирован.
А вот насчет того, что не повлияет на загрузку - еще как повлияет

Посмотри, только внимательно:

StoredProc.StoredProcUpdate.DatabaseName = 'SalaryODBC'
StoredProc.StoredProcUpdate.StoredProcName = 'EmployeeUpdate;1'
StoredProc.StoredProcUpdate.ParamData = <
    item
      StoredProc.StoredProcUpdate.DataType = ftInteger
      StoredProc.StoredProcUpdate.Name = '@RETURN_VALUE'
      StoredProc.StoredProcUpdate.ParamType = ptResult
    end
    item
      StoredProc.StoredProcUpdate.DataType = ftString
      StoredProc.StoredProcUpdate.Name = '@NameLeftEmployee'
      StoredProc.StoredProcUpdate.ParamType = ptInput
    end>


И куда по твоему должно присваиваться то, что написано между itemи end?  

P.S. надо срочно кондиционер чинить, то скоро у меня все работники перегреются :)


jack128   (2005-12-03 18:23:00) [5]

Макс Черных ©   (03.12.05 17:29) [12]
fStoredProc изначально равен nil,

это не так, он создается в конструкторе THandBook. И все таки, хотя указаная тобой ошибка, без сомнения есть, но на механизм загрузки она повлиять не может.


Макс Черных   (2005-12-03 17:29:00) [6]


> Но наврядли это имеет отнашение  к делу


Да ну?

Давайте посмотрим, у товарища DimaBr написано:

procedure THandBook.SetStoredProc(const Value: ThbStoredProc);
begin
fStoredProc.AssignTo(Value);
end;


При загрузке формы, fStoredProc изначально равен nil, и этому полю ничегоне присваивается. Неудивительно, что "Получается что подсвойство создаётся раньше свойства".

Это ведь вообще азы. Надо писать Assign как положено, и все будет работать без всяких DefineProperties.


jack128   (2005-12-02 21:30:00) [7]

Макс Черных ©   (01.12.05 21:32) [8]
а это совсем не одно и то-же.


Я бы сказал это прямо противоположные вещи ;)  Но наврядли это имеет отнашение  к делу.

DimaBr   (29.11.05 10:44) [7]
//fStoredProcShow.SetSubComponent(true);

раскомментируй эту строчку.


Макс Черных   (2005-12-02 17:01:00) [8]

2 DimaBr

Выдержка из Classes, занимательная, конечно.
Но все таки, каким образом AssignTo(Dest: TPersistent) у Вас превратился в AssignTo(Source: TPersistent) и самое главное - зачем?

Неудивительно, что при загрузке свойств все сходит с ума. Так как, там именно Assign и используется.


DimaBr   (2005-12-02 14:47:00) [9]

 TPersistent = class(TObject)
 private
   procedure AssignError(Source: TPersistent);
 protected
    procedure AssignTo(Dest: TPersistent); virtual;
   procedure DefineProperties(Filer: TFiler); virtual;
   function  GetOwner: TPersistent; dynamic;
 public
   destructor Destroy; override;
   procedure Assign(Source: TPersistent); virtual;
   function  GetNamePath: string; dynamic;
 end;


Макс Черных   (2005-12-01 21:32:00) [10]

public
  ...
  procedure AssignTo(Source: TPersistent);override;
  ...
end;


Что то тут явно перепутано. В модуле Classes объявлено:

protected
  procedure AssignTo(Dest: TPersistent); virtual;


Похоже перепутаны Assign и AssignTo, а это совсем не одно и то-же.


DimaBr   (2005-11-29 10:44:00) [11]

Ничего не получается.
При применении Вашего совета [3] в инспекторе пропадает вложенный компонент, остаётся как ссылка (то есть можно выбрать из уже имеющихся на форме). Помогите пожалуйста !
Вот урезал компонет до одного модуля и одного свойства.

unit HandBook;

interface

uses Classes, DBTables;

type
ThbStoredProc = class;
THandBook = class(TComponent)
 private
   fStoredProc: ThbStoredProc;
   procedure SetStoredProc(const Value: ThbStoredProc);
 public
   constructor Create(AOwner: TComponent);override;
   destructor Destroy; override;
 published
   property StoredProc: ThbStoredProc read fStoredProc write SetStoredProc;
 end;

ThbStoredProc = class(TPersistent)
 private
   fHandBook: TComponent;
   fStoredProcShow: TStoredProc;
   procedure SetStoredProcShow(const Value: TStoredProc);
   procedure WriteStoredProc(Writer: TWriter);
   procedure ReadStoredProc(Reader: TReader);
 public
   procedure DefineProperties(Filer: TFiler); override;
   constructor Create(AOwner: TComponent);
   destructor Destroy;override;
   procedure AssignTo(Source: TPersistent);override;
 published
   property StoredProcShow: TStoredProc read fStoredProcShow write SetStoredProcShow stored false;
end;

procedure Register;

implementation

{ THandBook }
constructor THandBook.Create(AOwner: TComponent);
begin
 inherited Create(AOwner);
 fStoredProc := ThbStoredProc.Create(self);
end;

destructor THandBook.Destroy;
begin
 fStoredProc.Free;
 inherited;
end;

procedure THandBook.SetStoredProc(const Value: ThbStoredProc);
begin
 fStoredProc.AssignTo(Value);
end;

{ ThbStoredProc }
constructor ThbStoredProc.Create(AOwner: TComponent);
begin
 inherited Create;
 fHandBook := AOwner;
 fStoredProcShow := TStoredProc.Create(nil);
 //fStoredProcShow.SetSubComponent(true);
end;

destructor ThbStoredProc.Destroy;
begin
 fHandBook := nil;
 fStoredProcShow.Free;
 inherited;
end;

procedure ThbStoredProc.SetStoredProcShow(const Value: TStoredProc);
begin
 fStoredProcShow := Value;
end;

procedure ThbStoredProc.AssignTo(Source: TPersistent);
begin
 if Source is ThbStoredProc then begin
   self.fStoredProcShow := ThbStoredProc(Source).StoredProcShow;
 end{if}
end;

procedure ThbStoredProc.DefineProperties(Filer: TFiler);
begin
 inherited;
 Filer.DefineProperty('StoredProcShow', ReadStoredProc,WriteStoredProc,true);
end;

procedure ThbStoredProc.ReadStoredProc(Reader: TReader);
begin
 fStoredProcShow := TStoredProc(Reader.ReadComponent(nil));
end;

procedure ThbStoredProc.WriteStoredProc(Writer: TWriter);
begin
 Writer.WriteComponent(fStoredProcShow);
end;

procedure Register;
begin
 RegisterComponents('Standard', [THandBook]);
end;

end.


DimaBr   (2005-11-29 09:25:00) [12]

Спасибо, буду пробывать.


Юрий Зотов   (2005-11-29 08:49:00) [13]

Для этого перекрываем метод DefineProperties и пишем к нему ReadXXX и WriteXXX (вызывая внутри ReadComponent и WriteComponent). А чтобы не было двойного сохранения, к объявлению свойства дописываем stored False.


DimaBr   (2005-11-29 08:35:00) [14]

То есть нужно, что бы запоминался не в родителе, а в классе TPersistent.
Для этого переопределяем WriteComponent в котором пишем

Procedure ThbStoredProc.WriteComponent(Writer: TWriter);
begin
 Writer.WriteComponent(fStoredProcUpdate);
end;

Я правильно мыслю ?


Юрий Зотов   (2005-11-28 18:55:00) [15]

fStoredProcUpdate создается с Owner=fHandBook и ему устанавливается SetSubComponent. Таким образом, он будет запоминаться внутри fHandBook, а не внутри ThbStoredProc - что мы и видим в DFM.

Видимо, Owner надо проставить в nil, а SetSubComponent убрать. Сохранять внутри ThbStoredProc, ручками (через DefineProperties и WriteComponent). И не забыть уничтожить в деструкторе ThbStoredProc.


DimaBr   (2005-11-28 17:07:00) [16]


type
THandBook = class(TComponent)
 private
   fStoredProc: ThbStoredProc;
   procedure SetStoredProc(const Value: ThbStoredProc);
 public
   constructor Create(AOwner: TComponent);override;
   destructor Destroy; override;override;
 published
   property StoredProc: ThbStoredProc read fStoredProc write SetStoredProc;
 end;

...

constructor THandBook.Create(AOwner: TComponent);
begin
 inherited Create(AOwner);
 fStoredProc := ThbStoredProc.Create(self);
...
end;

procedure THandBook.SetStoredProc(const Value: ThbStoredProc);
begin
 fStoredProc.AssignTo(Value);
end;

{ ThbStoredProc }
constructor ThbStoredProc.Create(AOwner: TComponent);
begin
 fHandBook := AOwner; //  << указаткль на родителя
 fStoredProcUpdate := TStoredProc.Create(fHandBook);
 fStoredProcUpdate.SetSubComponent(true);
end;
procedure ThbStoredProc.AssignTo(Source: TPersistent);
begin
 if Source is ThbStoredProc then begin
   self.fStoredProcUpdate := ThbStoredProc(Source).StoredProcUpdate;
 end{if}
end;


Юрий Зотов   (2005-11-28 15:03:00) [17]

1. Как объявлено свойство в самом компоненте?
2. Нигде в конструкторе не пропущено inherited?


Наверх

Титульная страница Поиск, карта сайта Написать письмо