Надежная перевозка оборудования автомобильным транспортом в Омск.

Си - Статьи - Загрузка компонентов

Как известно, С++Builder IDE сохранянет и загружает формы
и компоненты проекта в дизайнтайме из .dfm файла. Выполнение этой работы
поручено двум специальным классам TWriter и TReader. В статье
я покажу, как вы легко можете использовать эти классы для сохранения и
загрузки компонентов из файла


Сохранение компонентов в файл


Класс TWriter содержит многочисленные методы для
записи свойств компонентов в поток. Здесь я продемонстритую метод TWriter::WriteComponent(),
который может быть использован для сохранения всех свойств компонента
(и свойств субкомпонентов), обладающих способностью сохраняться в потоке,
включая свойства-события. Здесь показана полезная функция, которая использует
метод WriteComponent() для сохранения компонента в файле.

#include

#include

 

int __fastcall SaveComponent(AnsiString filename, TComponent* Component)

 {

  assert(Component != NULL);

  assert(Component->Owner != NULL);

 

  std::auto_ptrfs(new TFileStream(filename, fmCreate));

  std::auto_ptr Writer(new TWriter(fs.get(),4096));

  Writer->Root = Component->Owner;

  Writer->WriteComponent(Component);

  return Writer->Position;

 }


Класс TWrite предназначен для использования с объектами
типа TStream. Здесь я использовал указатель на объект типа TFileStream
в качестве первого параметра в конструкторе TWriter. Второй параметр
конструктора TWriter является целым числом, определяющим размер
внутреннего буфера TWriter сначала будет писать в этот буфер, а
затем в поток после заполнения буфера.


После создания объекта TWriter устанавливается значение свойства
Root и затем вызывается метод WriteComponent. Свойство Root
определяет владельца сохраняемого компонента. Класс TWriter будет
записывать в поток и свойства-события, если им были присвоены обработчики,
которые расположены в пределах секции __published владельца. Таким
образом, при сохранении компонента важным является то, что (1) компонент
и все его субкомпоненты имели того же владельца, и (2) все обработчики
событий компонента и его субкомпонентов были определены в пределах секции
__published владельца. Например, если Вы сохраняете объект типа
TTabControl, который содержит контролы, вы должны сделать так,
что бы все эти контролы имели того владельца, что и TTabControl
и все обработчики событий этих контролов определены в пределах секции
__published владельца. Первое ограничение не является большой проблемой,
если все элементы управления созданы во время разработки, если вспомнить
то, что родительская форма является владельцем всех созданных во время
разработки элементов управления. Однако, об этом ограничении надо помнить
при создании элементов управления во время выполнения.


Загрузка компонентов из файла


Класс TWriter имеет противоположный по применению
класс TReader, который предназначен для загрузки компонента из
потока. Как вы могли уже догадаться, специальный метод, предназначенный
для этого, носит название ReadComponent(). Ниже показана функция,
демонстрирующая, как используется метод TComponent::ReadComponent()
для загрузки компонента (включая его субкомпоненты) из файла.

int __fastcall LoadComponent(AnsiString filename, TComponent*& Component)

 {

  assert(Component != NULL);

  assert(Component->Owner != NULL);

 

  std::auto_ptrfs(new TFileStream(filename, fmOpenRead));

  std::auto_ptr Reader(new TReader(fs.get(),4096));

 


Reader->Root = Component->Owner;
TControl* Control = dynamic_cast(Component);
if(Control)
{
Reader->Parent = Control->Parent;
}

delete Component;
Component = NULL;

Reader->BeginReferences();
try
{
Component = Reader->ReadComponent(NULL);
}
__finally
{
Reader->FixupReferences();
Reader->EndReferences();
}

return Reader->Position;
}

Из за того, что оба класса являются производными от класса TFiler,
они обладают общим интерфейсом. Параметры конструктора класса TReader,
например, такие же, как и у конструктора класса TWriter. Аналогично
TReader имеет такое же свойство Root, которое играет такую
же роль. Тем не менее, стоит обратить внимание, что класс TReader
имеет дополнительное свойство Parent, которое необходимо установить,
если загружаемый компонент является производным от TControl. Необходимость
задания свойства Parent, возникает из-за того, что свойство TControl::Parent
не является сохраняемым в потоке.


Функция LoadComponent() предназначена для замены
существующего компонента на сохраненный. Вы определяете существующий компонент
посредством параметра Component, который возвратит указатель на
обновленный загруженный компонент. Таким образом, после того, как свойства
Root и Parent установлены, существующий компонент (параметр
Component) уничтожается и затем вместо него загружается сохраненный
компонент посредством вызова метода ReadComponent(). Вызову метода ReadComponent()
предшествует вызов BeginReference(), а затем после вызова ReadComponent()
следуют вызовы FixupReference() и EndReference(). Эти три
метода гарантируют то, что все компоненты будут загружены из потока до
того, как ссылки на них будут присвоены где-либо еще.


Заключение


Здесь не упомянут один момент, который вам необходим: классы
компонентов, загружаемых из файла, должны быть зарегистрированы, до того
как Вы выполните вызов LoadComponent(). Код к этой статье (доступный
на http://www.bridgespublishing.com/default.htm)
демонстрирует, как это можно сделать, и там имеются примеры использования
функций SaveComponent() и LoadComponent().

Автор: Damon Chandle. Перевод: В. Ермолаев. По материалам: www.bcbdey.ru.
Copyright © 2006-09.