Работа с отчетами Rave Report в режиме RunTime
Пример вызова процедуры GetListParentClassName:GetListParentClassName(MemoInfo.Lines, RvProjectRTR.ClassType);илиGetListParentClassName(MemoInfo.Lines, TRvProject); Как было сказано выше, для доступа к проекту отчета необходим класс TRaveProjectManager. Чтобы получить к нему доступ, необходимо обратиться к свойству «ProjMan» класса TRvProject. Как известно в проекте отчета Rave Report может содержаться несколько отчетов. Работа с отчетом осуществляется через класс TRaveReport. Для доступа к текущему активному отчету нужно обратиться к свойству «ActiveReport» класса TRaveProjectManager. Вот для свойства «ActiveReport» класса TRaveProjectManager и следует применить выше описанную процедуру GetListObjects для получения списка объектов из отчета. Для использования процедуры можно использовать, к примеру, такие строки кода: ... ListObjects.Clear; GetListObjects(ListObjects.Items, RvProjectRTR.ProjMan.ActiveReport, '', True); ... Посмотрите на результат работы процедуры GetListObjects. Вы наверняка сразу заметили одну особенность, что все имена классов представленных объектов начинаются с приставки «TRave…». Ну вот, зная имена классов, работать будет уже намного легче. Совет: Если известен некий класс, но неизвестно в каком модуле данный класс описан, то это можно выяснить с помощью поисковика файлов с поддержкой поиска текста внутри файлов. В поисковике задать маску для поиска «*.dcu» в папке «\Rave5\Lib», а в строке для поиска текста указать наименование класса, например: TRaveControl. Исследование объектов средствами технологии RTTI Получив список объектов, не мешало бы поподробнее получить информацию об интересующем объекте. В этом, безусловно, поможет технология RTTI. Если вы имеете опыт работы с RTTI, то можете пропустить данный раздел статьи. Примечание: В данной статье не будет достаточно подробно рассматриваться принцип работы с RTTI так как эта тема довольно-таки велика по объему. Будет рассмотрено только то, что поможет в дальнейшей работе. Более подробно с принципами работы технологии RTTI вы можете познакомиться в книге Стива Тейксейра и Ксавье Пачеко «DELPHI 5 Руководство разработчика. Том 2. Разработка компонентов и работа с базами данных». Процедуры, реализованные в этой статье, основаны на примерах из этой книги, и были несколько доработаны для работы с проектом, описываемым в данной статье. Для работы с RTTI в раздел проекта uses необходимо подключить модуль TypInfo. Для извлечения информации RTTI обычно требуется две структуры: PTypeInfo и PTypeData. Ниже приведена процедура, которая выводит базовую информацию об интересующем объекте.
procedure GetListClassInfo(ListInfo: TStrings; ClassX: TObject; ClearList:
Boolean = True);
var
// В данные структуры записывается информация об RTTI объекта
Class_PTI: PTypeInfo;
Class_PTD: PTypeData;
begin
if (ClassX = nil) or (ListInfo = nil) then
EXIT;
if ClearList then
ListInfo.Clear;
// Получение информации об RTTI объекта
Class_PTI := ClassX.ClassInfo;
Class_PTD := GetTypeData(Class_PTI);
// Вывод базовой информации об объекте
with ListInfo do
begin
Add('Базовая информация:');
Add(Format('Имя класса: '#9' %s',[Class_PTI.Name]));
Add(Format('Тип класса: '#9' %s',
[GetEnumName(TypeInfo(TTypeKind),
Integer(Class_PTI.Kind))]));
Add(Format('Размер объекта: '#9' %d',[ClassX.InstanceSize]));
Add(Format('Описан в модуле: '#9' %s',[Class_PTD.UnitName]));
Add(Format('Всего доступно свойств: %d', [Class_PTD.PropCount]));
if ClassX is TRaveControl then
begin
Add('Родительский компонент:');
Add(Format('Тип класса: %s',
[TRaveControl(ClassX).Parent.ClassName]));
Add(Format('Имя компонента: %s', [TRaveControl(ClassX).Parent.Name]));
end;
Add('Генеалогическое дерево класса:');
// Вывод информации о предках объекта
GetListParentClassName(ListInfo, ClassX.ClassType, False);
end;
end;
Примечание: Следует помнить, что в RTTI доступны только те свойства и методы, которые определены в секции published исследуемого объекта, т.е. те которые видны в инспекторе объ-ектов среды разработки Delphi. Свойства и методы необъявленные в секции published через технологию RTTI будут недоступны.
Следующая процедура выводит список наименований свойств, свойств-событий (методы) и тип свойств исследуемого объекта. Также данная процедура выводит текущие значения, присвоенные свойствам объекта. Для свойств типа tkClass (в этих свойствах храниться ссылка на некий объект) выводиться имя объекта, на который ссылается данное свойство. Если же это свойство не ссылается на объект, то будет выведено значение «NIL».
procedure GetListProperty(ListPropertys: TStrings; ClassX: TObject; AddObjects:
Boolean = False; ClearList: Boolean = True);
var
PropList: PPropList;
Class_PTI: PTypeInfo;
Class_PTD: PTypeData;
I, PropertyCount: Integer;
S, StrVal: string;
TmpObj: TObject;
begin
if (ClassX = nil) or (ListPropertys = nil) then
EXIT;
if ClearList then
ListPropertys.Clear;
Class_PTI := ClassX.ClassInfo;
Class_PTD := GetTypeData(Class_PTI);
if Class_PTD.PropCount <> 0 then
begin
// Выделение памяти под структуры TPropInfo, в зависимости от количества свойств объекта
GetMem(PropList, SizeOf(PPropInfo) * Class_PTD.PropCount);
try
// Заполнение PropList указателями на структуры TPropInfo
GetPropInfos(ClassX.ClassInfo, PropList);
for I := 0 to Class_PTD.PropCount - 1 do
// Добавляются свойства не являющиеся событиями
if not (PropList[I]^.PropType^.Kind = tkMethod) then
begin
// Извлечение текущего значения свойства
if PropList[I]^.PropType^.Kind = tkClass then
begin
TmpObj := GetObjectProp(ClassX, PropList[I]^.Name);
if TmpObj = nil then
StrVal := 'NIL'
else
// Если у объекта есть предок TComponent,
// то извлекается имя объекта иначе имя класса
if TmpObj is TComponent then
StrVal := TComponent(TmpObj).Name
else
StrVal := '(' + TmpObj.ClassName + ')';
end
else
StrVal := GetPropValue(ClassX, PropList[I]^.Name);
S := Format('%s: %s = %s', [PropList[I]^.Name,
PropList[I]^.PropType^.Name, StrVal]);
if AddObjects then
ListPropertys.AddObject(S, TObject(PropList[I]^.PropType^))
else
ListPropertys.Add(S);
end;
// Поиск свойств-событий
PropertyCount := GetPropList(ClassX.ClassInfo, [tkMethod], PropList);
ListPropertys.Add('*** Свойства-события ***');
// Добавляются свойства-события
for i := 0 to PropertyCount - 1 do
begin
S := Format('%s: %s', [PropList[I]^.Name, PropList[I]^.PropType^.Name]);
if AddObjects then
ListPropertys.AddObject(S, TObject(PropList[I]^.PropType^))
else
ListPropertys.Add(S);
end;
finally
// Освобождение ранее выделенной памяти
FreeMem(PropList, SizeOf(PPropInfo) * Class_PTD.PropCount);
end;
end;
end;
Отправить комментарий