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

Вниз

TStrings * не считывается из DFM   Найти похожие ветки 

 
murza   (2002-08-26 12:21) [0]

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


 
Игорь Шевченко ©   (2002-08-26 12:23) [1]

Правильно кажется. TStrings - абстрактный класс


 
murza   (2002-08-26 12:24) [2]

Чушь! Я ж не создаю TStrings. К тому же в TMemo Lines так же сделаны.


 
Skier ©   (2002-08-26 12:30) [3]

murza
А оно у тебя опубликовано ? :)


 
murza   (2002-08-26 12:34) [4]

Да, да __published. Редактор работает.


 
Игорь Шевченко ©   (2002-08-26 12:51) [5]

Memo.Lines - TMemoStrings


 
murza   (2002-08-26 12:58) [6]


> Игорь Шевченко © (26.08.02 12:51)
> Memo.Lines - TMemoStrings

Позвольте...
C:\Program Files\Borland\CBuilder5\Source\Vcl\stdctrls.pas:
TCustomMemo = class(TCustomEdit)
private
FLines: TStrings;
...
public
...
property Lines: TStrings read FLines write SetLines;
end;
...
TMemo = class(TCustomMemo)
published
...
property Lines;
...
end;
...
procedure TCustomMemo.SetLines(Value: TStrings);
begin
FLines.Assign(Value);
end;

(Правда совсем непонятно, за счет чего перерисовывается)


 
Skier ©   (2002-08-26 13:04) [7]

>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;


 
murza   (2002-08-26 13:08) [8]

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


 
Skier ©   (2002-08-26 13:10) [9]

>murza

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

???


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


> 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 не вызывается?


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

Код в студию


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

>murza


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


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


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


> Игорь Шевченко © (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() << paDialog; }
AnsiString __fastcall GetValue() { return "(TStrings)"; }
void __fastcall Edit() { ((TGlobFun*)GetComponent(0))->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:50) [14]

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


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


> 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;
}



 
MBo ©   (2002-08-26 14:18) [16]

пример на 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 14:33) [17]


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

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

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

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


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


> murza (26.08.02 12:21)

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

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

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


 
murza   (2002-08-27 10:10) [19]

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

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


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


> murza (27.08.02 10:10)


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

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


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


> Набережных С. (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-28 16:45) [22]

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

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-29 11:13) [23]

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

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

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


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

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


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

Да я добился правильного заполнения поля 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<TMyComponent*> (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-30 15:22) [26]

Ответ:

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.



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

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

Наверх




Память: 0.55 MB
Время: 0.017 c
1-35638
SomeQ
2002-09-01 10:08
2002.09.12
FindNext in RichEdit


3-35619
kest2
2002-08-22 11:25
2002.09.12
Oшибка!?


1-35636
lipskiy
2002-08-26 20:32
2002.09.12
Иконки с альфаканалом?


14-35906
Владимир Шевченко
2002-08-16 14:53
2002.09.12
Form1.Query Format


3-35607
OGR
2002-08-22 15:29
2002.09.12
Помогите разобраться с FieldTtpe при создании таблицы в RunTime