Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2002.09.12;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.008 c
1-35743
Cr@sh
2002-08-30 06:50
2002.09.12
Сведения о системе.


14-35894
kalenih
2002-08-19 14:09
2002.09.12
Привет


14-35865
gray_k
2002-08-15 18:17
2002.09.12
где взять


4-35946
Пастор
2002-07-21 14:57
2002.09.12
Как убрать кнопку проги с панели задач на АРI ?


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





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский