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

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

TStrings * не считывается из DFM [D5, Win95/98]


Страницы:   1 2

murza ©   (2002-08-26 12:21:00) 

Есть небольшая проблема. Есть компонент. Есть свойство
__property TStrings *Definition = {read = FDefinition, write = SetDefinition};
На него, кстати, редактор повешен.
Строки замечательно пишутся в DFM. Проблема в том, что при чтении из DFM SetDefinition не вызывается. И еще он не вызывается при MyComponent1->Definition->Text = "String1\nString2";
Кажется он вызывается только при MyComponent1->Definition = MyStringList;
ЗЫ у меня BCB5


Набережных С.   (2002-08-30 15:22:00) [1]

Ответ:

unit Component1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
TMyComponent = class(TComponent)
private
FDefinition: TStrings;
procedure SetDefinition(const Value: TStrings);
procedure Loaded;override;
public
constructor Create(AOwner: TComponent);override;
destructor Destroy;override;
procedure Assign(Source: TPersistent);override;
published
property Definition: TStrings read FDefinition write SetDefinition;
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents("NSN Controls", [TMyComponent]);
end;

type
TMyStrings = class(TStringList)
protected
procedure DefineProperties(Filer: TFiler); override;
end;

{ TMyComponent }

procedure TMyComponent.Assign(Source: TPersistent);
begin
FDefinition.Assign((Source as TMyComponent).FDefinition);
inherited;
end;

constructor TMyComponent.Create(AOwner: TComponent);
begin
inherited;
FDefinition:=TMyStrings.Create;//или чего там у тебя
end;

destructor TMyComponent.Destroy;
begin
FDefinition.Free;
inherited;
end;

procedure TMyComponent.Loaded;
begin
//Здесь все свойства уже считаны из DFM
ShowMessage("Loaded!");
inherited;
end;

procedure TMyComponent.SetDefinition(const Value: TStrings);
begin
FDefinition.Assign(Value);
end;

{ TMyStrings }

procedure TMyStrings.DefineProperties(Filer: TFiler);
begin
if Filer is TWriter then ShowMessage("Me write!")
else ShowMessage("Me load!");{Filer is TReader}
inherited;//<-Здесь и происходит считывание и запись из/в DFM
end;

end.


murza   (2002-08-30 11:47:00) [2]

Да я добился правильного заполнения поля FDefinition.
Вот только метод SetDefinition не вызывается.
Вот вам код:

class PACKAGE TMyComponent : public TComponent {
private:
protected:
TStrings *FDefinition;
void __fastcall SetDefinition(TStrings *Value);
public:
__fastcall TMyComponent(TComponent* Owner);
__fastcall ~TMyComponent();
virtual void __fastcall Assign(TPersistent* Source);
TMyComponent& operator=(TPersistent &Source);
__published:
__property TStrings * Definition = {read = FDefinition, write = SetDefinition};
};
//-------------------------------------------------------------
__fastcall TMyComponent::TMyComponent(TComponent* Owner) : TComponent(Owner) {
ShowMessage("TMyComponent::TMyComponent called");
FDefinition = new TStringList;
}
//---------------------------------------------------------------------------
__fastcall TMyComponent::~TMyComponent() {
ShowMessage("TMyComponent::~TMyComponent called");
delete FDefinition;
}
//---------------------------------------------------------------------------
void __fastcall TMyComponent::SetDefinition(TStrings *Value) {
ShowMessage("TMyComponent::SetDefinition called");
FDefinition->Assign(Value);
}
//---------------------------------------------------------------------------
void __fastcall TMyComponent::Assign(TPersistent* Source) {
ShowMessage("TMyComponent::Assign called");
try {
TMyComponent* MyComponent;
if ((MyComponent = dynamic_cast (Source) ) != 0)
SetDefinition(MyComponent->FDefinition);
}
catch(...) {
ShowMessage("Error dynamic casting");
}
}
//---------------------------------------------------------------------------
TMyComponent& TMyComponent::operator=(TPersistent &Source) {
ShowMessage("TGlobFun::operator= called");
Assign(&Source);
return *this;
}

Ни оператор копирования, ни метод Assign, ни SetDefinition не вызываются.
ВОПРОС: Как мне лучше всего сделать так, чтоб при считывании из DFM мне можно было отловить заполнение свойства. Я же не могу делать это в конструкторе, который вызывается раньше.


Набережных С.   (2002-08-29 14:56:00) [3]

Извини, не понимаю твоей проблемы. Тот "компонент", который я привел в примере прелестно будет редактироваться в дизайне, и сохраняться в DFM, и загружаться оттуда. Если же тебе надо вмешаться в процесс выгрузки-загрузки, то нужно перекрыть метод DefineProperties у компонента, либо объявить потомка TStrinList и перекрыть у него.
Ты все-же поисследуй мой пример, включив отладочные DCU, заберись поглубже в исходники, НЕ ПОЖАЛЕЙ ВРЕМЕНИ, тогда и разберешься со всей этой "механикой".


murza   (2002-08-29 11:13:00) [4]

Большое спасибо, конечно, но я хочу сделать компонент и поставлять его пользователю, причем:
- компонент должен быть редактируемым в design-time и изменения должны сохраняться и учитываться в run-time
- компонент должен уметь копироваться-вставляться через буфер обмена.
Как ни странно это звучит, для сохранения всей информации об объекте я выбрал TStrings, в виду соображений: у других компонентов типа TMemo он стремируется, значит и у меня он будет стремироваться, и к тому мне нужен был экспорт/импорт в текст.

Теперь я все больше склоняюсь к мысли, что для того чтобы заставить строки стремироваться необходимо либо внутри использовать экземпляры другого типа, имеющего связь компонентом (наподобие TMemoStrings) либо перегрузить какой-либо из методов, унаследованных от TPersistent (насколько я понимаю, именно этот класс связан со стремированием).

Подскажите, прав ли я, и вкаком направлении мне лучше действовать.
Спасибо.


Набережных С.   (2002-08-28 16:45:00) [5]

Думаю, лучше всего поступить так. Погоняй под отладчиком вот этот пример:

TMyComponent = class(TComponent)
private
FDefinition: TStrings;
procedure SetDefinition(const Value: TStrings);
public
constructor Create(AOwner: TComponent);override;
destructor Destroy;override;
published
property Definition: TStrings read FDefinition write SetDefinition;
end;

constructor TMyComponent.Create(AOwner: TComponent);
begin
inherited;
FDefinition:=TStringList.Create;//или чего там у тебя
end;

destructor TMyComponent.Destroy;
begin
FDefinition.Free;
inherited;
end;

procedure TMyComponent.SetDefinition(const Value: TStrings);
begin
FDefinition.Assign(Value);
end;

var
MyComponent1: TMyComponent;

const
ComponentFile = "MyComponent.aaa";

procedure TForm1.Button1Click(Sender: TObject);
var
FS:TStream;
begin
if MyComponent1 = nil then MyComponent1:=TMyComponent.Create(Self);
// MyComponent1.Definition.Text:="Aaa"#13#10"Bbb";
MyComponent1.Definition:=Memo1.Lines;
FS:=TFileStream.Create(ComponentFile,fmCreate);
try
FS.WriteComponent(MyComponent1);
finally
FS.Free;
end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
FS:TStream;
begin
if MyComponent1 = nil then MyComponent1:=TMyComponent.Create(Self);
MyComponent1.Definition.Text:="";
Memo1.Lines.Text:="";
FS:=TFileStream.Create(ComponentFile,fmOpenRead);
try
FS.ReadComponent(MyComponent1);
Memo1.Lines.Assign(MyComponent1.Definition);
finally
FS.Free;
end;
end;


После этого, думаю, тебе все станет ясно.
P.S. На си уж сам переведи - все-таки здесь дельфийский форум :))


murza   (2002-08-28 12:10:00) [6]


> Набережных С. (27.08.02 15:36)
> Разумеется, нет. Получив указатель на объект(FDefinition),
> компилятор непосредственно вызывает его метод. После St:=MyComponent1.FDefinition
> и St, и MyComponent1.FDefinition указывают на один и тот-же
> объект и, соответственно, MyComponent1.SetDefinition(St)
> теряет всякий смысл.
>

Получается что мы можем написать delete Memo1->Lines; Печально...

> То-же самое происходит и с DFM. Только в этом случае вызывается
> метод DefineProperties объекта, на который указывает FDefinition.
> Похоже, ты путаешь понятия объекта и указателя на него(а
> может, мне только так кажется:)). FDefinition содержит указатель
> на объект. И St после присвоения будет содержать тот-же
> указатель. Поройся в архивах этого форума - вопросы на подобные
> темы появляются здесь с удручающей регулярностью.

Я ничего не понямаю. Причем здесь метод чтения? Разве при чтении из DFM не должен использоватся метод SetDefinition?
Мне это действительно нужно, так как изменения во время design-time не сохраняются (точнее, сохраняются, но не загружаются), а копирование - вставка игнорируется уже сделанные изменения.


Набережных С.   (2002-08-27 15:36:00) [7]


> murza (27.08.02 10:10)


> Хотя я думал что иначе

Разумеется, нет. Получив указатель на объект(FDefinition), компилятор непосредственно вызывает его метод. После St:=MyComponent1.FDefinition и St, и MyComponent1.FDefinition указывают на один и тот-же объект и, соответственно, MyComponent1.SetDefinition(St) теряет всякий смысл.
То-же самое происходит и с DFM. Только в этом случае вызывается метод DefineProperties объекта, на который указывает FDefinition. Похоже, ты путаешь понятия объекта и указателя на него(а может, мне только так кажется:)). FDefinition содержит указатель на объект. И St после присвоения будет содержать тот-же указатель. Поройся в архивах этого форума - вопросы на подобные темы появляются здесь с удручающей регулярностью.


murza   (2002-08-27 10:10:00) [8]

Может быть и так.
Хотя я думал что иначе:
St:=MyComponent1.FDefinition;
St.Text:="String1\nString2";
MyComponent1.SetDefinition(St);

Потому что метод записи свойства Text неконстантный (не знаю есть ли такая терминология у дельфистов). Лень проверять. Но почему же они из DFM не считываются?


Набережных С.   (2002-08-26 16:07:00) [9]


> murza (26.08.02 12:21)

Исполнение конструкции MyComponent1->Definition->Text = "String1\nString2";
можно представить так:
var
St:TStrings;

St:=MyComponent1.FDefinition;
St.Text:="String1\nString2";

Теперь понятно?


murza   (2002-08-26 14:33:00) [10]


> MBo © (26.08.02 14:18)
> A1.Lines:=Memo1.Lines;//setlines вызывается

понятно что вызывается

> A1.Lines.Assign(Memo2.Lines);//не вызывается

я думал что в таких ситуациях (неконстантный метод) сначала свойство читается, а потом записывается
А вообще надо вопрос надо было прочитать.


MBo   (2002-08-26 14:18:00) [11]

пример на Delphi

unit AA;

interface
uses classes,graphics,controls,Sysutils,dialogs;
type
TA=class(TCustomControl)
private
FLines: TStrings;
FCounter:Integer;
procedure SetLines(const Value: TStrings);
public
constructor Create(AOwner:TComponent);override;
procedure Paint;override;
published
property Lines:TStrings read FLines write SetLines;
end;
procedure Register;

implementation

{ TA }

constructor TA.Create(AOwner: TComponent);
begin
inherited;
FLines:=TStringList.Create;
Width:=200;
Height:=200;
end;

procedure TA.Paint;
var i:integer;
begin
inherited;
Canvas.Brush.Style:=bsClear;
Canvas.TextOut(0,0,"SetLines has been called "+IntToStr(FCounter)+" times");
for i:=0 to FLines.Count-1 do
Canvas.TextOut(0,12+i*12,Flines[i]);
end;

procedure TA.SetLines(const Value: TStrings);
begin
FLines.Assign(Value);
Inc(FCounter);
ShowMessage("SetLines called");
Refresh;
end;

procedure Register;
begin
RegisterComponents("Samples",[TA]);
end;

end.

-------------------

procedure TForm1.Button1Click(Sender: TObject);
begin
A1.Lines:=Memo1.Lines;//setlines вызывается
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
A1.Lines.Assign(Memo2.Lines);//не вызывается, сразу идет TStrings.Assign
A1.Refresh;
end;


murza   (2002-08-26 13:56:00) [12]


> Skier © (26.08.02 13:50)
> Хотелось бы взглянуть на код конструктора TGlobFun...
> И какой класс реально в Definition...

__fastcall TGlobFun::TGlobFun(TComponent* Owner)
: TComponent(Owner),FFunc(FHANSEN,2)
{
//...skipped...
FDefinition = FuncToText(&FFunc);
}
//----------------------------------------
TStringList *FuncToText(GLOBFUNC *Func)
{
//...skipped...
TStringList *Result = new TStringList;
//...skipped...
return Result;
}


Skier   (2002-08-26 13:50:00) [13]

>murza
Хотелось бы взглянуть на код конструктора TGlobFun...
И какой класс реально в Definition...


murza   (2002-08-26 13:40:00) [14]


> Игорь Шевченко © (26.08.02 13:13)
> Код в студию

Сами напросились. Разбирайте:
class PACKAGE TGlobFun : public TComponent
{
//...skipped...
private:
//...skipped...
GLOBFUNC FFunc;
TStrings * FDefinition;
protected:
//...skipped...
int __fastcall SetFunc(GLOBFUNC f);
void __fastcall SetDefinition(TStrings *Def);
public:
//...skipped...
void __fastcall EditFuncDefinition();
__published:
//...skipped...
__property TStrings *Definition = {read = FDefinition, write = SetDefinition};
};
//----------------------------------------
class TGlobFuncDefinitionPropertyEditor : public TPropertyEditor
{
__fastcall TGlobFuncDefinitionPropertyEditor (void)
: Dsgnintf::TPropertyEditor (Designer, 0) {}
TPropertyAttributes __fastcall GetAttributes ()
{ return TPropertyAttributes() EditFuncDefinition(); }
};
//----------------------------------------
void __fastcall TGlobFun::SetDefinition(TStrings *Def) {
// ShowMessage("TGlobFun::SetDefinition");
GLOBFUNC *pFunc;
pFunc = TextToFunc(Def);
if (pFunc != NULL) SetFunc(*pFunc);
delete pFunc;
}
//----------------------------------------
int __fastcall TGlobFun::SetFunc(GLOBFUNC f)
{
//...skipped...
FFunc = f;
//...skipped...
delete FDefinition;
FDefinition = FuncToText(&FFunc);
//...skipped...
}
//----------------------------------------
void __fastcall TGlobFun::EditFuncDefinition()
{
TGFCodeForm *GFCodeForm = new TGFCodeForm(Application, &FFunc, false);
if (GFCodeForm->ShowModal() == mrOk)
if (FFunc != *(GFCodeForm->ParsedFunc))
SetFunc(*(GFCodeForm->ParsedFunc));
GFCodeForm->Free();
}

А теперь по русски. Есть компонент - задача. Функция то бишь. И она должна по мановению волжебной палочки уметь превращаться в текст и обратно. Definition - свойство - набор строк тестового описания.

> Skier © (26.08.02 13:15)
> > Кажется он вызывается
> Это очень интересное словечко...На ощупь идёшь что ли ?

Если убрать комментарии: // ShowMessage("TGlobFun::SetDefinition");В описанных случаях сообщение не показывается. "Кажется" выражает сомнение. Уж не вызывает ли BCB этот метод, игнорируя собщение.


Skier   (2002-08-26 13:15:00) [15]

>murza


> Кажетсяон вызывается


Это очень интересное словечко...На ощупь идёшь что ли ?


Игорь Шевченко   (2002-08-26 13:13:00) [16]

Код в студию


murza   (2002-08-26 13:11:00) [17]


> Skier © (26.08.02 13:10)
> ???

Хорошо, поясню:

> Есть небольшая проблема. Есть компонент. Есть свойство
> __property TStrings *Definition = {read = FDefinition, write
> = SetDefinition};
> На него, кстати, редактор повешен.
> Строки замечательно пишутся в DFM. Проблема в том, что при
> чтении из DFM SetDefinition не вызывается. И еще он не вызывается
> при MyComponent1->Definition->Text = "String1\nString2";
> Кажется он вызывается только при MyComponent1->Definition
> = MyStringList;
> ЗЫ у меня BCB5

Почему SetDefinition не вызывается?


Skier   (2002-08-26 13:10:00) [18]

>murza

> Это не меняет дела

???


murza   (2002-08-26 13:08:00) [19]

> Skier © (26.08.02 13:04)
Это не меняет дела (хотя теперь понятно, почему перерисовывается). Смотри вопрос.


Skier   (2002-08-26 13:04:00) [20]

>murza

А как насчёт этого :


constructor TCustomMemo.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width := 185;
Height := 89;
AutoSize := False;
FWordWrap := True;
FWantReturns := True;
FLines := TMemoStrings.Create;
TMemoStrings(FLines).Memo := Self;
end;


Страницы:   1 2

Наверх

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