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

Вниз

Контейнер компонета   Найти похожие ветки 

 
veb   (2003-08-16 14:13) [0]

Здравствуйте!

Нужна помощь настоящих мастеров. Проблема в загрузке компонентов. Какие свойства или методы необходимо дописать в мои классы.

Такая ситуация:
Есть два компонента TElem и TElemContainer. Один (TElemContainer) содержит в себе другой (TElem). Компоненты находятся
в разных модулях причем TElem ничего не знает о классе TElemContainer.
Задача:
При загрузке проекта корректно восстановить структуру классов, т.е. загрузить TElem обратно в контейнер.

TElem = class( TComponent)
end;

TElemContainer = class( TComponent)
protected
procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override; // Сохранение инфы про детишек в dfm
published
property Elem : TElem read FElem write FElem;
end;

P.S. Очень важно, что TElem обособленный компонент и не может вызывать методы класcа TElemContainer.


 
Skier   (2003-08-16 14:18) [1]

>veb (16.08.03 14:13)
Может быть стоит коллекцию использовать ?


 
Юрий Зотов   (2003-08-16 14:35) [2]

> veb (16.08.03 14:13)

Наиболее просто, конечно, сделать коллекцию, но если предусматривается визуальное наследование форм, то могут возникнуть проблемы и тогда лучше делать именно компоненты. Кроме GetChldren могут потребоваться еще GetChildOwner, GetChildParent, SetChildOrder, HasParent, GetParentComponent, SetParentComponent и т.п.

Посмотрите, как это сделано, например, у TDataSet и TField. Или у TMenu и TMenuItem.


 
ayder   (2003-08-16 23:29) [3]

Юрий Зотов> TDataSet и TField - это не совсем то. Т.к. TField знает свой NDataSet и TMenuItem знает TMenu.

У TElem должно быть свойство FParent : TComponent;
А у TElemContainer перегружен метод Loaded, в котором соотвествующие компоненты ( ( Component is TElem ) and ( TElem(Component).Parent = Self ) добавляются в контейнер.


 
veb   (2003-08-18 11:26) [4]

Загрузка выгрузка работает отлично, однако при запуске приложения получаю вот такую ошибку.
raised exception class EClassNotFound with message "Class
TElem not found". Классы естественно зарегистрированы.

Кто может помочь? Какие еще необходимы методы?

to Юрий Зотов
неужели необходимо реализовывать все методы, подсказанные Вами.
Фактически все что мне необходимо работает, что же происходит при запуске?

Вот такая структура классов. TElemList является и Owner и Parent для TElem

TElem = class(TComponent)
private
FParent : TComponent;
FTest : Integer;
protected
procedure ReadState(Reader: TReader); override;
public
function HasParent: Boolean; override;
function GetParentComponent: TComponent; override;
constructor Create( AOwner: TComponent); override;
destructor Destroy; override;
property Parent: TComponent read FParent write FParent;
published
property Test: Integer read FTest write FTest;
end;

TElemList = class(TComponent)
private
FElem : TElem;
protected
procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
function GetChildOwner: TComponent; override;
public
procedure AddElem;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Elem: TElem read FElem write FElem;
end;

.....
function TElemList.GetChildOwner: TComponent;
begin
Result := Self;
end;

procedure TElemList.GetChildren(Proc: TGetChildProc; Root: TComponent);
begin
inherited;
Proc( FElem);
end;
......
function TElem.GetParentComponent: TComponent;
begin
Result := FParent;
end;

procedure TElem.ReadState(Reader: TReader);
begin
inherited ReadState( Reader);
FParent := Reader.Parent;
end;


 
Skier   (2003-08-18 11:47) [5]

>veb (18.08.03 11:26) [4]
Покажи код где вылетает ошибка.


 
veb   (2003-08-18 14:30) [6]

to Skier
Вот информация из окна Call Stack

ТReader.FindComponentClass["TElem"]
CreateComponent
ТReader.ReadComponent[nil]
ТReader.ReadDatalnner($C01E30]
ТReader.ReadData($C01E30]
ТComponent ReadState($C02440]
ТControl.ReadState($C02440]
TWinControl.ReadS tate($C02440]
TCustomForm.ReadState($C02440]
ТReader.ReadRootComponent($C01E30]
ТStream.ReadComponent($C01E30]
InternalReadComponentRest"TForm1",4194304,$С01ЕЗО]
lnitComponent[TForm1]
InitlnheritedComponent[$C01E30, Form]
TCustomForm.Create($C01SC4]
ТApplication.CreateForm[TForm1,[no value]]
Project1

Ошибка вылетает вот здесь:

Classes.pas

function TReader.FindComponentClass(const ClassName: string): TComponentClass;
begin
TPersistentClass(Result) := GetFieldClass(Root, ClassName);
if not Assigned(Result) and Assigned(FLookupRoot) and (FLookupRoot <> Root) then
TPersistentClass(Result) := GetFieldClass(FLookupRoot, ClassName);
if Assigned(FOnFindComponentClass) then
FOnFindComponentClass(Self, ClassName, Result);
if (Result = nil) or not Result.InheritsFrom(TComponent) then // ERROR
ClassNotFound(ClassName);
end;

Но что это дает?


 
veb   (2003-08-18 14:30) [7]

to Skier
Вот информация из окна Call Stack

ТReader.FindComponentClass["TElem"]
CreateComponent
ТReader.ReadComponent[nil]
ТReader.ReadDatalnner($C01E30]
ТReader.ReadData($C01E30]
ТComponent ReadState($C02440]
ТControl.ReadState($C02440]
TWinControl.ReadS tate($C02440]
TCustomForm.ReadState($C02440]
ТReader.ReadRootComponent($C01E30]
ТStream.ReadComponent($C01E30]
InternalReadComponentRest"TForm1",4194304,$С01ЕЗО]
lnitComponent[TForm1]
InitlnheritedComponent[$C01E30, Form]
TCustomForm.Create($C01SC4]
ТApplication.CreateForm[TForm1,[no value]]
Project1

Ошибка вылетает вот здесь:

Classes.pas

function TReader.FindComponentClass(const ClassName: string): TComponentClass;
begin
TPersistentClass(Result) := GetFieldClass(Root, ClassName);
if not Assigned(Result) and Assigned(FLookupRoot) and (FLookupRoot <> Root) then
TPersistentClass(Result) := GetFieldClass(FLookupRoot, ClassName);
if Assigned(FOnFindComponentClass) then
FOnFindComponentClass(Self, ClassName, Result);
if (Result = nil) or not Result.InheritsFrom(TComponent) then // ERROR
ClassNotFound(ClassName);
end;

Но что это дает?


 
Skier   (2003-08-18 15:09) [8]

>veb (18.08.03 11:26) [4]
Странно что это баг происходит только
при запуске приложения.
А где ты регистрируешь классы ?
Если перенести регистрацию в секцию initialization ?


 
veb   (2003-08-19 00:20) [9]

to Skier
Огромное спасибо! Просто нет слов как вы выручили. Работает. Хорошо бы теперь объяснить почему.
Почему регистрацию класса необходимо проводить в том же модуле в разделе Initialization? Ранее, делал Package и все классы и компоненты регистрировал в отдельном модуле Register.pas. Почему в этот раз исключение?


 
Camus   (2003-08-19 09:08) [10]

> veb (19.08.03 00:20) [9]

Это не исключение, а скорее правило. При регистрации в отдельном модуле имеет значение порядок загрузки и может произойти обращение к еще не зарегистрированному классу. А при его регистрации в initialization его же модуля это исключено.


 
veb   (2003-08-19 10:54) [11]

to Camus
Уточните, пожалуйста, в моем пониманиии если компонент или класс зарегистрирован, то Delphi уже должен знать о его существовании. Судя по вашему ответу, при каждом запуске любого приложения происходит регистрация. Извините, за навязчивость, но хотелось бы разобраться с этим механизмом.


 
Camus   (2003-08-19 11:06) [12]

> veb (19.08.03 10:54) [11]
> если компонент или класс зарегистрирован, то Delphi уже должен
> знать о его существовании

Так оно и есть. Но это же в design-time, а в Вашем случае класс должен быть известен и в run-time - то есть, самой программе, без всякой Delphi. Для этого он должен быть зарегистрирован через RegisterClass. Для форм и лежащих на них коипонентов код такой регистрации компилятор вставляет автоматически, а другие классы надо регистрировать ручками (не всегда, конечно, а только если в программе используются какие-то нестанлартные примочки).


 
Skier   (2003-08-19 11:07) [13]

>veb (19.08.03 10:54) [11]
У тебя чтение и запись данных из контейнера происходит только
при работе из под IDE или и в самой программе ?


 
veb   (2003-08-19 11:55) [14]

to Camus
Все понятно. Спасибо.

to Skier
и в самой программе и в Design-Time. А для чего этот вопрос?


 
Skier   (2003-08-19 12:03) [15]

>veb (19.08.03 11:55) [14]
А для того что если бы всё происходило только в Design-Time и
твоя ошибка оставалась бы то это было бы весьма странно и как это
дело побороть я бы затруднился ответить, а вот если есть ещё и
run-time, то твоя ошибка вполне логична (впрочем как и её решение) и тебе про неё уже хорошо всё рассказал Camus


 
veb   (2003-08-19 12:06) [16]

to Camus
Все понятно. Спасибо.

to Skier
Не совсем понятен вопрос. Это по поводу Initialization или я не дописал какие-то методы. Меня очень смущает, что из восьми предложенных Юрием Зотовым методов я воспользовался только тремя.
И в программе и в Design-Time мне приходится вносить элемент в контейнер и удалять и изменять значение свойств у самого элемента.


 
veb   (2003-08-19 12:09) [17]

to Skier
Еще раз спасибо!



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

Форум: "Основная";
Текущий архив: 2003.09.01;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.5 MB
Время: 0.023 c
1-1478
Foxy
2003-08-18 12:37
2003.09.01
Запуск планировщика заданий


3-1284
Zorik
2003-08-11 09:16
2003.09.01
Табличные даные в Interbase


9-1272
Leroy
2003-02-27 12:41
2003.09.01
Мастера посмотрите игрульку


6-1520
Карелин Артем
2003-06-26 13:39
2003.09.01
Отсылка почты через прокси.


6-1541
BlackSun
2003-06-26 18:42
2003.09.01
RasGetEntryDialParams - не могу получить номер телефона





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский