![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
ПодСвойство компонента
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?