Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.06.18;
Скачать: CL | DM;

Вниз

ПодСвойство компонента   Найти похожие ветки 

 
DimaBr   (2005-11-28 11:54) [0]

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

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-11-28 15:03) [1]

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


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


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 18:55) [3]

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

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


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

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

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

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


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

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


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

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


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

Ничего не получается.
При применении Вашего совета [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.


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

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


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

protected
  procedure AssignTo(Dest: TPersistent); virtual;


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


 
DimaBr   (2005-12-02 14:47) [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-02 17:01) [10]

2 DimaBr

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

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


 
jack128 ©   (2005-12-02 21:30) [11]

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


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

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

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


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


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


Да ну?

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

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


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

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


 
jack128 ©   (2005-12-03 18:23) [13]

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

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


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


> 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 20:01) [15]

Макс Черных ©   (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]
надо срочно кондиционер чинить, то скоро у меня все работники перегреются :)

я не против ;)


 
jack128 ©   (2005-12-03 20:22) [16]

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


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

2 jack128.

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

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


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


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



Страницы: 1 вся ветка

Текущий архив: 2006.06.18;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.036 c
1-1147460541
Mao
2006-05-12 23:02
2006.06.18
подскажите решение клиент/сервер


15-1148318340
TUser
2006-05-22 21:19
2006.06.18
"Доктор Живаго"


15-1148510953
Копир
2006-05-25 02:49
2006.06.18
Уважаемые господа, владельцы телефонов Siemens


3-1145527323
samalex
2006-04-20 14:02
2006.06.18
Выделить целую часть десятичного числа


2-1148921178
JTAG
2006-05-29 20:46
2006.06.18
Господпа в компоненте StringGrid в ячейке пользователю можно