Меню

Ошибка a component named already exists

As far as my exploration along this line, yes the problem of «already exists» stems from having intances of the editor with the same value for the Name property. As another work around do not visually create the editor(s). Create a new component based on TForm/TFrame/TPanel for the editor(s) you want the user to be able to create multiple instances of. You will have to hand code the creation & deletion of any sub-controls, Setting their properties within your code and assigning values — anything from V_Btn = new TBitBtn(this), V_Btn->Color = clTeal, to V_Btn->OnClick = Close_The_Window. BUT NEVER assign a value to the Name property of any component in the new class and do not set the Name property of the editor once you have created an instance of the editor. Treat the Name property for editor as if it did not exist. After you have created the class and added it to your project the following is valid :

TMyeditor* Editor_01 = new TMyeditor(Main_Form);
TMyeditor* Editor_02 = new TMyeditor(Main_Form);
  Editor_01->Parent = Tab_Sheet_Addresses;
  Editor_02->Parent = Tab_Sheet_Billing;

The more complex the design concept for your editor the more effort you will undergoe to code the class. However this approach will resolve the «already exists» error.

            End of answer.

The following is tangental to the original question as it is an extension of what you may want to further do with your code & I write it to help you along should it be the case. The following allows you to efficiently store/retrieve the editor(s) and its published properties such as position on the user’s screen, themes, etc. If you’ve gone the above route, add the following :

void RegisterClassesWithStreamingSystem(void)
{   
  // Make sure that as part of the startup   
  // code TMyEditor is registered   
  // with the streaming system.   
  #pragma startup RegisterClassesWithStreamingSystem  
  Classes::RegisterClass(__classid(TMyEditor)); 
}

You can now ComponentToString <—> StringToComponent[*1] the editor(s).
You can now create a simple database of each editor saving it [*2] and re-creating the editor(s) at runtime. Saving & Recreating is almost entirely done by the TReader/TWriter objects.
{It is worth while to read about TReader/TWriter which is included in the Delphi help file}

[ Presupposing you have an instances of TMyEditor you want to save called Editor_01 & Editor_02 and
you’ve created the dataset and assigned it to a TClientDataSet named «CDS» ]

//How to write the Editors
String_Version_Of_Editor = ComponentToString(Editor_01);
CDS->Insert();
CDS->FieldByName("Data")->AsString = String_Version_Of_Editor;
CDS->Post();
String_Version_Of_Editor = ComponentToString(Editor_02);
CDS->Insert();
CDS->FieldByName("Data")->AsString = String_Version_Of_Editor;
CDS->Post();

//How to read, create an instance of, set the Owner of 
//(allowing for automatic destruction/deletion
// if desired, Vis-à-vis Let the compiler/runtime package handle that), 
//& setting the form's Parent
AnsiString   String_Version_Of_Editor; 
TWinControl* New_Editor;
String_Version_Of_Editor = CDS->FieldByName("Data")->AsString;
//The next line creates/constructs the new editor
New_Editor = StringToComponent(String_Version_Of_Editor);
//The next line sets the new editor's Owner to Main_Form 
//It also assigns Main_Form the responsibility of object cleanup
Main_Form->Insert(New_Editor);
//The next line sets the Editor's Parent causing it to be part of the 
//displayed user interface (it has been invisble since creation)
New_Editor->Parent = Tab_Sheet_Addresses;
//Move on to the next editor;
CDS->Next();
String_Version_Of_Editor = CDS->FieldByName("Data")->AsString;
New_Editor = StringToComponent(String_Version_Of_Editor);
Main_Form->Insert(New_Editor);
New_Editor->Parent = Tab_Sheet_Billing;

People who read the above who are astute will have noted that in the above code the New_Editor is of type TWincontrol not TMyEditor — though it likely should have been. However I did this to draw attention to the fact that problematically the TReader object in Delphi which is really doing the work of converting a string to a component object instance creates/constructs any object which has been registered with the streaming class via RegisterClass. In this manner explicit creation of the editor via explicitedly naming it’s type is avoided. If thought is given to the design of TMyEditor and its descendents the only change required to the code is to change TWinControl* to TMyEditor* — even that is not required if published properties beyond TWinControl* are not accessed outside the scope of TMyEditor — Example TMyEditor has access to the variables whose values it is editing and does not require this information to be supplied to the editor.(If working from a DataModule, #include the datamodule’s header into TMyEditor).

Side Note:
You may have a utility to know what class was read from the database so that you may place the instance where it belongs. To do this #include <typeinfo> into your code.
Example : If you have instances of TMyEditor, TMyEditor_Generation_01, TMyEditor_Generation_02, etc writen to the database the following will allow you to examine the instances read at runtime for placement into the user interface :

 if (typeid(New).name() == "TMyEditor *")
   New_Editor->Parent = Tab_Sheet_Addresses;
  else
   if (typeid(New).name() == "TMyEditor_Generation_01 *")
     New_Editor->Parent = Tab_Sheet_Billing;
   else
    if (typeid(New).name() == "TMyEditor_Generation_02 *")
      New_Editor->Parent = Tab_Sheet_Other_Editor;

typeid(__).name() will return a string which is the name of the class, in this case will also inculde » *».

The above allows ANY object(s) to be stored in the database and recreated. The entries within the database are not required to be related. The TReader object buried in Delphi’s code will decide at runtime what they are and use the correct constructor.

[*1] Note : The ComponentToString and StringToComponent are examples in the delpi/c++ help file.

[*2] Note : What is being saved are the published properties, therefore in your editor class any values you want stored and retrieved which are not already inherited and published should be declared in the __published section of your new class. Those items may also be custom objects, for those you will likely code custom specific methods/functions for the read/write access specifiers in defining the _property. I would suggest translating any complex object into a string value for ease of examining your code while under development.

 
Димон
 
(2005-03-01 12:02)
[0]

Есть примерно такой код, который выполняется в одном из методов другой формы:

kForm := TMyForm.Create(Application);
try
  Result := kForm.ShowModal = mrOk;
  if Result then
     kForm.SaveResults(ResultObject);
finally
  kForm.Release();
end;

После этого кода результаты диАлогового ввода пользователя, сохраненные командой SaveResults в ResultObject, неким образом обрабатываются.

Бывают случае когда обработка заканчивается с ошибкой. После этого в пириведенном выше коде возбуждается исключение указанное в сабже.

Вопрос: что приводит к такой ошибке?

Проде бы TComponent должен сам заботиться о выборе имени дабы избежать конфликта имен в рамках своего owner. С чем может быть связано отсутствие такого подбора в моем случае?


 
Shirson ©
 
(2005-03-01 12:07)
[1]

В каком месте кода идёт возбуждение и что за обработка идёт?


 
clickmaker ©
 
(2005-03-01 12:10)
[2]


> Проде бы TComponent должен сам заботиться о выборе имени
>

в ран-тайме не должен


 
Димон
 
(2005-03-01 12:12)
[3]


> В каком месте кода идёт возбуждение и что за обработка идёт?

Сразу после.

Но связь интересующей меня ошибки с ошибкой при обработке ResultObject это только мое предположение, т.к. ошибка происходит у заказчика. И заказчик не может описать что он делал до получения «a component named … already exists».

Я предполагаю, что форма как-то некорректно удаляется или еще что. Собственно я бы мог разобраться с формированием имени в модуле classes. Но я бы очень хотел прежде чем это делать (все-таки там немало кода) услышать мнения общественности. Может кто с этим сталкивался.


 
Юрий Зотов ©
 
(2005-03-01 12:13)
[4]

Нужно видеть:
— код SaveResults;
— ResultObject (хотя бы, как объявлен, где и как создается и уничтожается);
— код обработки.


 
Димон
 
(2005-03-01 12:15)
[5]


> в ран-тайме не должен

Раааазве. А ты попробуй :)))

showmessage(TForm2.create(application).name);
showmessage(TForm2.create(application).name);
showmessage(TForm2.create(application).name);
showmessage(TForm2.create(application).name);

Прекрасно отработает каждый раз генеря новое имя 🙂


 
Юрий Зотов ©
 
(2005-03-01 12:18)
[6]

> Вроде бы TComponent должен сам заботиться о выборе имени

Выбор уникального имени — задача дизайнера, а не компонента. Откройте DFM — там имена уже жестко проставлены. Они же жестко прописаны в коде, как ссылочные published-поля и по ним как раз и идет инициализация этих полей при чтении DFM (см. FieldAddress).


 
Димон
 
(2005-03-01 12:20)
[7]


>  [4] Юрий Зотов ©   (01.03.05 12:13)

Добрый день, Юрий.

1) Код обработки показать не могу. Это тысяч 15 строк. Фактически это построение поискового sql запроса к базе sql на основе развернутых метаданных и текущего состояния ResultObject.

2) Если ближе к телу, то код такой
CLASS FUNCTION TForm_MLDocumentFilter._Execute(
  const aFrameFilterClass: TFrame_MLChapterItemClass;
  const aFilter: IMLFilter;
  const aCls: TMLChapterItemClass): Boolean;
VAR
  kForm: TForm_MLDocumentFilter;
  kFilter: IMLFilter;
BEGIN
  // Создаем копию фильтра
  kFilter := aFilter.__Clone();
  // Создаем форму
  kForm := TForm_MLDocumentFilter.fCreate(aFrameFilterClass, kFilter, aCls);
  try
     // Выполняем форму в модальном режиме
     Result := kForm.ShowModal = mrOk;
     // Если пользователь нажал кнопку OK то копируем из временного объекта в постоянный
     if Result then aFilter.__Assign(kFilter); // Это SaveResults из примера
  finally
     kForm.Release();
  end;
END;

где fCreate это конструктор вызывающий inherited Create(application) + несколько простых действий.

3) Код saveResults — это просто копирование значений объекта.


 
Димон
 
(2005-03-01 12:22)
[8]


>  [6] Юрий Зотов ©   (01.03.05 12:18)

Тода как объяснить работоспособность моего кода из [5]?


 
Юрий Зотов ©
 
(2005-03-01 12:27)
[9]

> Димон   (01.03.05 12:20) [7]

Загадок стало еще больше. Надо сымитировать ошибку при обработке и ходить отладчиком.

Ясно одно — при ошибке не уничтожается какой-то контейнер (например, форма), а потом этот же контейнер загружается — отсюда и дубликат имен. Если ошибки нет, то контейнер уничтожается и при загрузке все проходит ОК.


 
Димон
 
(2005-03-01 12:30)
[10]


>  [9] Юрий Зотов ©   (01.03.05 12:27)


> Загадок стало еще больше

Да сам в загадках.


> Надо сымитировать ошибку при обработке и ходить отладчиком.

Не получается — она, зараза, неведенная. Т.е. некоторая последовательность играет роль.


> Ясно одно — при ошибке не уничтожается какой-то контейнер

Опять же повторю, что вроде бы в этом случае должно сгенериться новое уникальное имя. Мой пример из [5] показывает это.

Т.е. такое ощущение, что что-то уничтожилось но не до конца :))


 
Димон
 
(2005-03-01 12:39)
[11]

Еще подлость в том, что подебужить classes нормально не получается: все строки съехавшие, т.е. часто ходишь по пустым местам, тогда как у нормальных строк не стоит слева точечка :(((


 
MU
 
(2005-03-01 12:42)
[12]

Destroys the form and frees its associated memory.

procedure Release;

Description

Use Release to destroy the form and free its associated memory.

Release does not destroy the form until all event handlers of the form and event handlers of components on the form have finished executing. Release also guarantees that all messages in the form»s event queue are processed before the form is released. Any event handlers of the form should use Release instead of Free. Failing to do so could lead to an access violation.

Note: Release returns immediately to the caller. It does not wait for the form to be freed before returning.


 
Димон
 
(2005-03-01 12:44)
[13]

Понимаешь, в чем дело, как работает Release я в общем то знаю (код то доступен). Другой вопрос: ну и что? Ну допустим я пытаюсь второй раз открыть ту же форму. Ну и что? Пример из [5] показывает, что факт неудаленности предыдущей формы не должен оказыать никакого влияния — должно сгенериться новое уникальное имя.


 
Юрий Зотов ©
 
(2005-03-01 12:53)
[14]

> Димон   (01.03.05 12:22) [8]

> Тода как объяснить работоспособность моего кода из [5]?

Ответ лежит в модуле Classes:

function TReader.ReadRootComponent(Root: TComponent): TComponent;
 function FindUniqueName(const Name: string): string;

Вот эта самая FindUniqueName и формирует суффикс «_цифра». Но работает все это только для глобальных компонентов, а имена внутренних компонентов жестко прописаны в DFM и грузятся оттуда без всякой модификации (ведь иначе будет невозможно проинициализировать соответствующие поля контейнера).

В любом случае видим, что сам компонент о выборе своего имени не заботится. Он только проверяет его в SetName.


 
KSergey ©
 
(2005-03-01 12:54)
[15]

> [13] Димон   (01.03.05 12:44)
> должно сгенериться
> новое уникальное имя.

Вам тут уже сказали не раз: НЕ ДОЛЖНО!! Не должно — и все тут!
И никакой ваш пример тут не убедителен, я сам на это не раз натыкался (к стати, может форма и генерит новое имя верно, но в ней ли дело? Что у вас там создается — хрен знает. Может и не в ней дело.

Теперь еще. После вызова Release, как вы знаете, сразу объект не уничтожается. В этом может быть как раз и косяк.

Я взял за правило динамически создаваемым объектам давать имя — пустую строку. Тогда никто никогда не ругается.

Опять же в этом коде просто НЕТ СМЫСЛА в Release. Это излишняя нагрузка на систему, не более.


 
KSergey ©
 
(2005-03-01 12:56)
[16]

> [14] Юрий Зотов ©   (01.03.05 12:53)
> имена внутренних компонентов жестко прописаны в DFM

Блин, точно! Он же не просто объект создает, а форму… Туплю…

К стати, именно в Release тут может и быть косяк: если объект таки успеет разрушиться — то ошибки нет, если не успевает — ошибка. Выкинуть. Глупость это здесь полная.


 
clickmaker ©
 
(2005-03-01 13:00)
[17]


> Димон   (01.03.05 12:44) [13]

а тебе так принципиально это release? Делай просто Free


 
Юрий Зотов ©
 
(2005-03-01 13:03)
[18]

> Димон   (01.03.05 12:44) [13]

> Ну допустим я пытаюсь второй раз открыть ту же форму.
> Ну и что?

Не открыть, а загрузить. И при чтении из DFM первого же внутреннего компонента формы выясняется, что компонент с таким именем на этой форме уже есть. И приплыли.

Скорее всего, причина именно в этом.

> Пример из [5] показывает…

См. [14]. Для внутренних компонентов пример из [5] неприменим.


 
Димон
 
(2005-03-01 13:45)
[19]


>  [18] Юрий Зотов ©   (01.03.05 13:03)

Привет с внутренними компонентами неприминим — т.к. внутренние компоненты я не создаю. Это раз.


>  [16] KSergey ©   (01.03.05 12:56)

Мой пример очень даже убедителен. Для форм нет необъходимости задавать уникальные имена.

Мне не сложно — я очищаю имя. Это не проблема. Конечно же все работает.

Проблема в том, что я не понимаю такое поведение — если имя не уникально, то ошибки нет, но только в том случае, если раньше не было где-то как-то возникшего исключения. Знал бы где! Такое ощущение, что механизм выделения имен нарушается. Как? Фиг его знает. Потому и спрашиваю.


 
Димон
 
(2005-03-01 13:46)
[20]


> Привет

пример 🙂


 
KSergey ©
 
(2005-03-01 13:49)
[21]

> [19] Димон   (01.03.05 13:45)
> Потому и спрашиваю.

Внимательно вдумайтесь в термин ЮЗ «внутренние компоненты».
Признаюсь, я не сразу въехал, как только понял -все стало ясно.

PS
Если уж так нужна подсказка: в вашем примере [5] форма — явно пустая. А можеи и не в этом дело… (к ЮЗ: но ведь я могу создать 2 экземпляра одной и той же формы! Любой!)


 
Димон
 
(2005-03-01 13:56)
[22]


>  [21] KSergey ©   (01.03.05 13:49)

Не пустая :)))

Братья, вы в общем-то о чем-то не том говорите. Я так понимаю, что с такой ситуацией вы просто не сталкивались 🙂  

Здесь есть явное нарушение работы «выделятеля уникальных имен» по причине сложно наведенной ошибки.

Собственно вопрос о алгоритме выделения имен. Что там предположительно может сломаться. :))


 
Димон
 
(2005-03-01 14:02)
[23]

Собственно в алгоритме я со временем сам разберусь. Сейчас исправил пока очисткой имени. Но вопрос все-таки волнует, что может так сломаться, что форма не может снова быть создана. :)) И если кто-то с таким же сталкивался, то буду крайне рад получить данную информацию.


 
BlackTr
 
(2005-03-01 14:22)
[24]

У меня такая фигня была на 5 делфи, вылечилось установкой обновлений…
До конца так и не вьехал в чем причина была 🙂


 
Димон
 
(2005-03-01 14:24)
[25]

Во! ЗдрАвая информация. Есть у меня ощущение, что глюк 🙂


 
Юрий Зотов ©
 
(2005-03-01 16:09)
[26]

> Димон   (01.03.05 13:45) [19]

> Привет с внутренними компонентами неприминим — т.к. внутренние
> компоненты я не создаю.

Пишем: TForm2.Create(Application).Show — и видим форму со всеми ее компонентами. Мы их создавали? Нет, мы создавали только саму форму. Но они же есть — значит, кто-то их создал?

Так откуда же они взялись, как Вы считаете? И что в свете этого означает процитированная Ваша фраза, раз Вы сами говорите, что форма не пустая?


 
Димон
 
(2005-03-01 16:28)
[27]

Юрий, при всем моем уважении, ей богу вы придираетесь к словам 🙂

Я привел пример, что и как я создаю. Зависимые компоненты также создаются. Я лично непосредственно это не делаю.

Все мое утверждение было о том, что в любом случае при создании формы (даже той, которая разработана в design time) имя должно выставиться уникальным, что и демонстрирует пример из [5].

:))


 
Юрий Зотов ©
 
(2005-03-01 18:03)
[28]

> Димон   (01.03.05 16:28) [27]

> ей богу вы придираетесь к словам

Да мне-то что? Это не я придираюсь, а программа, которая не работает.

> Зависимые компоненты также создаются. Я лично непосредственно
> это не делаю.

А какая программе разница, чей код вызвал Create — Ваш или Борланловский?

> Все мое утверждение было о том, что в любом случае при
> создании формы (даже той, которая разработана в design time)
> имя должно выставиться уникальным, что и демонстрирует пример
> из [5].

Сорри, мне не хочется повторять в третий раз [14] и [18]. Очень советую внимательно посмотреть TReader.ReadRootComponent в Classes.


 
Димон
 
(2005-03-01 18:09)
[29]

Контрольный вопрос, или я что-то не понимаю?

Причем здесь внутренние компоненты? Ругается то на имя формы! Именно оно «already exists», а не имя внутренних компонентов.

Указанные методы я смотрел. Да, не очень детально. Но я как раз и не понимаю, какие могут быть причины, чтобы не делать суффикс «_xxx» к имени формы.

Собственно о том и спрашиваю. Может знаете 🙂


 
Димон
 
(2005-03-01 18:10)
[30]

Кстати да, я не сказал в вопросе, что ругается на имя формы, а не на имя внутреннего компонента. Прошу прощения, не подумал, что это важно.

🙂


 
Димон
 
(2005-03-01 18:14)
[31]

Понимаете ли, если бы я смоделировал ситуацию ошибки (я говорил, что знаю ее только на словах), то мог бы понять, что нарушается в этом механизме. Если не с использование «use debug dcu», то хоть cpu бы просмотрел.

Но смотря на алгоритм наделения компонентов уникальными номерами я не могу понять, что в нем может пойти не так.

Собственно надежда на то, что кто-то с этим вопросом разбирался.

Всем спасибо.


 
Юрий Зотов ©
 
(2005-03-01 18:35)
[32]

> Димон   (01.03.05 18:10) [30]
> Кстати да, я не сказал в вопросе, что ругается на имя формы, а
> не на имя внутреннего компонента. Прошу прощения, не подумал,
> что это важно.

Дим, ну ни фига себе! Это же в корне переворачивает ситуацию. Выходит, мы 30 постов просто не понимали друг друга.

Начинаем сначала:
— приведите все же имя формы, на которое ругается;
— кто является ее Owner»ом — Application или кто-то еще?


 
Димон
 
(2005-03-01 18:40)
[33]


>  [32] Юрий Зотов ©   (01.03.05 18:35)

Повторно прошу прощения, Юрий.

1) Ругается на «TForm_MLDocumentFilter». Где ругается, не знаю. Т.к. посторю, что не могу смоделировать ошибку — все со слов нашей техподдержки, которые лично видели ошибку, но не знают предысторию ее возникновения.

2) Application


 
Набережных С. ©
 
(2005-03-01 18:47)
[34]


> kForm.Release();

Возможно, к моменту второй попытки выполнить этот код тот экземпляр , который был создан при первом обращении, еще не уничтожен. Ну а так как имя у всех TMyForm одно и то-же, загружаемое из ресурсов, то и получаем эту ошибку. Поставь точку останова в OnDestroy, если дело в этом, то сразу обнаружишь. А имена компонентов на форме уникальны только в пределах этой формы.


 
Димон
 
(2005-03-01 18:55)
[35]


>  [34] Набережных С. ©   (01.03.05 18:47)

не в этом дело:))) [5] показывает, что ты можешь создавать сколько угодно одинаковых форм. Об уникальности имен позаботится сам vcl.


 
Набережных С. ©
 
(2005-03-01 19:00)
[36]


> Димон   (01.03.05 18:55) [35]

Попробуй все-таки заменить Release на Free. Ну для моего спокойствия:) Тем более, что релиз здесь вроде как и ни к чему…


 
Димон
 
(2005-03-01 19:06)
[37]


>  [36] Набережных С. ©   (01.03.05 19:00)

да я уже заменил:)
Самая проблема теперь протестировать. Ошибку мне так и не удалось смоделировать. Когда-то давно, давно, только когда я написал этот блок я видел сам пару раз эту ошибку. Теперь никак — не могу смоделировать:((((((


 
Набережных С. ©
 
(2005-03-01 19:35)
[38]

Ну могу только сказать, что в такой конструкции(с Free) у меня никогда ни единой проблемы не было. Прошелся поиском, такая ошибка генерится только в методе TComponent.ValidateRename. Копай, где и как он вызывается — вставка, удаление, переименование.
I>
> Теперь никак — не могу смоделировать

А может, ее уже и нету?<


 
Anatoly Podgoretsky ©
 
(2005-03-01 19:48)
[39]

Набережных С. ©   (01.03.05 19:00) [36]
Попробуй все-таки заменить Release на Free.
Набережных С. ©   (01.03.05 19:00) [36]
Попробуй все-таки заменить Release на Free. Ну для моего спокойствия:) Тем более, что релиз здесь вроде как и ни к

Release должен применяться внутри объекта (класса), вот с ним были проблемы при применении извне.
А Free снаружи, проблем тоже ни когда не было.


 
Димон
 
(2005-03-01 20:11)
[40]


>  [38] Набережных С. ©   (01.03.05 19:35)

может и нету :))


>  [39] Anatoly Podgoretsky ©   (01.03.05 19:48)

Проблемы? Можно подробнее? 🙂 Какие, например.


 
Anatoly Podgoretsky ©
 
(2005-03-01 20:24)
[41]

Зависание


Что касается моего исследования в этом направлении, да, проблема «уже существует» проистекает из наличия в редакторе того же значения для свойства Name. В качестве другой работы не создавайте визуально редактор (ы). Создайте новый компонент на основе TForm / TFrame / TPanel для редактора (ов), для которого пользователь должен иметь возможность создавать несколько экземпляров. Вам нужно будет вручную создать и удалить любые субэлементы управления, установить их свойства в коде и присвоить значения — от V_Btn = new TBitBtn (this), V_Btn-> Color = clTeal до V_Btn-> OnClick = Close_The_Window . НО НИКОГДА не присваивайте значение свойству Name любого компонента в новом классе и не устанавливайте свойство Name редактора после создания экземпляра редактора. Относитесь к свойству Name для редактора как к несуществующему. После того, как вы создали класс и добавили его в свой проект, допустимо следующее:

TMyeditor* Editor_01 = new TMyeditor(Main_Form);
TMyeditor* Editor_02 = new TMyeditor(Main_Form);
  Editor_01->Parent = Tab_Sheet_Addresses;
  Editor_02->Parent = Tab_Sheet_Billing;

Чем сложнее концепция дизайна для вашего редактора, тем больше усилий вы приложите для написания кода. Однако этот подход разрешит ошибку «уже существует».

            End of answer.

Следующее имеет отношение к исходному вопросу, поскольку оно является продолжением того, что вы май хотите продолжить работу с вашим кодом, и я пишу его, чтобы помочь вам, если это так. Следующее позволяет вам эффективно сохранять / извлекать редактор (ы) и его опубликованные свойства, такие как положение на экране пользователя, темы и т. Д. Если вы пошли по вышеуказанному пути, добавьте следующее:

void RegisterClassesWithStreamingSystem(void)
{   
  // Make sure that as part of the startup   
  // code TMyEditor is registered   
  // with the streaming system.   
  #pragma startup RegisterClassesWithStreamingSystem  
  Classes::RegisterClass(__classid(TMyEditor)); 
}

Теперь вы можете ComponentToString <—> StringToComponent [* 1] редактор (ы). Теперь вы можете создать простую базу данных для каждого редактора, сохранив ее [* 2] и заново создав редакторы во время выполнения. Сохранение и воссоздание почти полностью выполняется объектами TReader / TWriter. {Стоит прочитать о TReader / TWriter, который включен в файл справки Delphi}

[Предположим, у вас есть экземпляры TMyEditor, которые вы хотите сохранить, с именем Editor_01 и Editor_02, и вы создали набор данных и назначили его TClientDataSet с именем «CDS»]

//How to write the Editors
String_Version_Of_Editor = ComponentToString(Editor_01);
CDS->Insert();
CDS->FieldByName("Data")->AsString = String_Version_Of_Editor;
CDS->Post();
String_Version_Of_Editor = ComponentToString(Editor_02);
CDS->Insert();
CDS->FieldByName("Data")->AsString = String_Version_Of_Editor;
CDS->Post();

//How to read, create an instance of, set the Owner of 
//(allowing for automatic destruction/deletion
// if desired, Vis-à-vis Let the compiler/runtime package handle that), 
//& setting the form's Parent
AnsiString   String_Version_Of_Editor; 
TWinControl* New_Editor;
String_Version_Of_Editor = CDS->FieldByName("Data")->AsString;
//The next line creates/constructs the new editor
New_Editor = StringToComponent(String_Version_Of_Editor);
//The next line sets the new editor's Owner to Main_Form 
//It also assigns Main_Form the responsibility of object cleanup
Main_Form->Insert(New_Editor);
//The next line sets the Editor's Parent causing it to be part of the 
//displayed user interface (it has been invisble since creation)
New_Editor->Parent = Tab_Sheet_Addresses;
//Move on to the next editor;
CDS->Next();
String_Version_Of_Editor = CDS->FieldByName("Data")->AsString;
New_Editor = StringToComponent(String_Version_Of_Editor);
Main_Form->Insert(New_Editor);
New_Editor->Parent = Tab_Sheet_Billing;

Проницательные люди, прочитавшие вышеизложенное, заметят, что в приведенном выше коде New_Editor имеет тип TWincontrol. не TMyEditor — хотя, скорее всего, должно было быть. Однако я сделал это, чтобы привлечь внимание к тому факту, что проблематично объект TReader в Delphi, который действительно выполняет работу по преобразованию строки в экземпляр объекта компонента, создает / конструирует Любой объект, который был зарегистрирован в потоковом классе через RegisterClass. Таким образом избегается явное создание редактора с явным указанием его типа. Если продумать дизайн TMyEditor и его потомков, единственное изменение, необходимое в коде, — это изменить TWinControl * на TMyEditor * — даже это не требуется, если опубликованные свойства за пределами TWinControl * не доступны за пределами TMyEditor — Пример TMyEditor имеет доступ к переменным, значения которых он редактирует, и не требует предоставления этой информации редактору (при работе из DataModule, # включить заголовок модуля данных в TMyEditor).

Боковое примечание: у вас может быть утилита, чтобы узнать, какой класс был прочитан из базы данных, чтобы вы могли разместить экземпляр, которому он принадлежит. Сделать это #include <typeinfo> в ваш код. Пример: если у вас есть экземпляры TMyEditor, TMyEditor_Generation_01, TMyEditor_Generation_02 и т. Д., Записанные в базу данных, следующее позволит вам проверить экземпляры, прочитанные во время выполнения, для размещения в пользовательском интерфейсе:

 if (typeid(New).name() == "TMyEditor *")
   New_Editor->Parent = Tab_Sheet_Addresses;
  else
   if (typeid(New).name() == "TMyEditor_Generation_01 *")
     New_Editor->Parent = Tab_Sheet_Billing;
   else
    if (typeid(New).name() == "TMyEditor_Generation_02 *")
      New_Editor->Parent = Tab_Sheet_Other_Editor;

typeid (__) .name () вернет строку, которая является именем класса, в этом случае также будет добавлен «*».

Вышеуказанное позволяет ЛЮБОЕ объект (ы), который будет сохранен в базе данных и воссоздан. Записи в базе данных не обязательно должны быть связаны. Объект TReader, скрытый в коде Delphi, решит во время выполнения, что они собой представляют, и будет использовать правильный конструктор.

[* 1] Примечание. ComponentToString и StringToComponent являются примерами в файле справки delpi / c ++.

[* 2] Примечание. Сохраняются опубликованный свойства, поэтому в вашем классе редактора Любой значения, которые вы хотите сохранить и получить, которые еще не унаследованы и не опубликованы, должны быть объявлены в разделе __published вашего нового класса. Эти элементы также могут быть настраиваемыми объектами, для которых вы, вероятно, будете кодировать специальные специальные методы / функции для спецификаторов доступа для чтения / записи при определении _property. Я бы посоветовал перевести любой сложный объект в строковое значение для облегчения изучения вашего кода во время разработки.

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Ошибка a certificate chain could not be built to a trusted root authority 0x800b010a
  • Ошибка 999 альфа банк