Форум: "Компоненты";
Текущий архив: 2006.06.18;
Скачать: [xml.tar.bz2];
ВнизПодСвойство компонента Найти похожие ветки
← →
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;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.015 c