Написание собственных движков баз данных

Top  Previous  Next

FastReport позволяет строить отчеты не только на основе данных, определенных в приложении. Вы также можете определить свои собственные источники данных (подключения к БД, таблицы, запросы) прямо в отчете. В комплекте с FastReport идут движки для ADO, BDE, IBX, DBX, FIB. Вы можете создать собственный движок и подключить его к FastReport.

 

На рисунке показана иерархия классов, предназначенных для создания движков баз данных. Зеленым цветом выделены компоненты нового движка.

 

 

_img2

 

Как видно, стандартный набор компонентов движка БД включает в себя Database, Table и Query. Вы можете реализовать все эти компоненты, или только некоторые из них (например, многие БД не имеют компонента типа Table). Также вы можете реализовать компоненты, не входящие в стандартный набор (например, аналог StoredProc).

 

Рассмотрим подробнее базовые классы.

 

TfrxDialogComponent - базовый класс для всех невизуальных компонентов, которые могут быть помещены в отчет FastReport. В нем не определено каких-либо важных свойств и методов.

 

       Класс TfrxCustomDatabase является базовым для написания компонент типа TDatabase.

 

TfrxCustomDatabase = class(TfrxDialogComponent)

protected

   procedure SetConnected(Value: Boolean); virtual;

   procedure SetDatabaseName(const Value: String); virtual;

   procedure SetLoginPrompt(Value: Boolean); virtual;

   procedure SetParams(Value: TStrings); virtual;

   function GetConnected: Boolean; virtual;

   function GetDatabaseName: String; virtual;

   function GetLoginPrompt: Boolean; virtual;

   function GetParams: TStrings; virtual;

public

   procedure SetLogin(const Login, Password: String); virtual;

   property Connected: Boolean read GetConnected write SetConnected default False;

   property DatabaseName: String read GetDatabaseName write SetDatabaseName;

   property LoginPrompt: Boolean read GetLoginPrompt write SetLoginPrompt default True;

   property Params: TStrings read GetParams write SetParams;

end;

 

       В классе определены следующие свойства:

 

- Connected является ли подключение к БД активным;

- DatabaseName имя БД;

- LoginPrompt надо ли запрашивать пароль при поключении к БД;

- Params параметры подключения.

 

       От данного класса наследуется компонент типа TDatabase. Для его реализации необходимо перекрыть все виртуальные методы и вынести нужные свойства в секцию published. Также необходимо добавить свойства, специфичные для вашего компонента.

 

       Классы TfrxDataset, TfrxCustomDBDataset, TfrxDBDataset обеспечивают функции доступа к данным. Ядро FastReport использует эти компоненты для навигации и обращения к полям набора данных. В данном случае они являются частью общей иерархии и не представляют интереса.

 

TfrxCustomDataSet - базовый класс для компонентов БД, производных от TDataSet. От этого класса наследуются компоненты - аналоги Query, Table, StoredProc. По сути, класс представляет собой обертку над TDataSet.

 

TfrxCustomDataset = class(TfrxDBDataSet)

protected

   procedure SetMaster(const Value: TDataSource); virtual;

   procedure SetMasterFields(const Value: String); virtual;

public

   property DataSet: TDataSet;

   property Fields: TFields readonly;

   property MasterFields: String;

   property Active: Boolean;

   property DBConnected: Boolean;

published

   property Filter: String;

   property Filtered: Boolean;

   property Master: TfrxDBDataSet;

end;

 

В классе определены следующие свойства:

 

- DataSet - ссылка на внутренний объект типа TDataSet;

- Fields - ссылка на DataSet.Fields;

- Active - активен ли набор данных;

- DBConnected подключен ли набор данных к компоненту TfrxXXXDatabase;

- Filter - выражение для фильтрации;

- Filtered - активна ли фильтрация;

- Master ссылка на источник данных, являющийся основным. Применяется для связей типа master-detail.

- MasterFields список пар полей вида field1=field2. Применяется для связей типа master-detail.

 

 

       TfrxCustomTable - базовый класс для компонентов БД типа Table. Класс является оберткой над компонентом типа Table.

 

TfrxCustomTable = class(TfrxCustomDataset)

protected

   function GetIndexFieldNames: String; virtual;

   function GetIndexName: String; virtual;

   function GetTableName: String; virtual;

   procedure SetIndexFieldNames(const Value: String); virtual;

   procedure SetIndexName(const Value: String); virtual;

   procedure SetTableName(const Value: String); virtual;

published

   property MasterFields;

   property TableName: String read GetTableName write SetTableName;

   property IndexName: String read GetIndexName write SetIndexName;

   property IndexFieldNames: String read GetIndexFieldNames write SetIndexFieldNames;

end;

 

       В классе определены следующие свойства:

 

- TableName имя таблицы;

- IndexName имя индекса;

- IndexFieldNames имена индексных полей.

 

От данного класса наследуется компонент типа Table. Для его реализации необходимо определить недостающие свойства, как правило, Database. Также необходимо перекрыть виртуальные методы из классов TfrxCustomDataset, TfrxCustomTable.

 

TfrxCustomQuery - базовый класс для компонентов БД типа Query. Класс является оберткой над компонентом типа Query.

 

TfrxCustomQuery = class(TfrxCustomDataset)

protected

   procedure SetSQL(Value: TStrings); virtual; abstract;

   function GetSQL: TStrings; virtual; abstract;

public

   procedure UpdateParams; virtual; abstract;

published

   property Params: TfrxParams;

   property SQL: TStrings;

end;

 

В классе определены свойства, общие для всех компонентов Query - SQL и Params. Т.к. разные компоненты Query имеют разную реализацию параметров (например, TParams, TParameters), свойство Params имеет тип TfrxParams и является оберткой над конкретным типом параметров.

 

В данном классе определены следующие методы:

 

- SetSQL - должен установить свойство SQL компонента типа Query;

- GetSQL - должен вернуть свойство SQL компонента типа Query;

- UpdateParams - должен скопировать значения параметров в компонент типа Query. Если компонент Query имеет параметры типа TParams, то копирование осуществляется стандартной процедурой frxParamsToTParams.

 

 

Рассмотрим создание движка БД на примере IBX. Полный исходный текст движка можно найти в каталоге SOURCE\IBX. Здесь мы будем приводить выдержки из исходного текста с комментариями и некоторыми поправками.

 

Компоненты IBX, вокруг которых мы будем строить обертку - TIBDatabase, TIBTable, TIBQuery. Соответственно, наши компоненты будут называться TfrxIBXDatabase, TfrxIBXTable, TfrxIBXQuery.

 

Еще один компонент, который мы должны создать - TfrxIBXComponents, он будет помещен в палитру компонент FastReport при регистрации движка в среде Delphi. При помещении этого компонента в проект Delphi автоматически добавит ссылку на модуль нашего движка в список uses. На этот компонент удобно возложить еще одну задачу - определить у него свойство DefaultDatabase, которое ссылается на уже имеющееся в проекте подключение к БД. По умолчанию все компоненты TfrxIBXTable и TfrxIBXQuery будут ссылаться на это подключение.

Компонент необходимо наследовать от класса TfrxDBComponents:

 

TfrxDBComponents = class(TComponent)

public

   function GetDescription: String; virtual; abstract;

end;

 

Единственная функция должна возвращать описание, например 'IBX Components'. Реализация компонента TfrxIBXComponents следующая:

 

type

TfrxIBXComponents = class(TfrxDBComponents)

private

   FDefaultDatabase: TIBDatabase;

   FOldComponents: TfrxIBXComponents;

public

   constructor Create(AOwner: TComponent); override;

   destructor Destroy; override;

   function GetDescription: String; override;

published

   property DefaultDatabase: TIBDatabase read FDefaultDatabase write FDefaultDatabase;

end;

 

var

IBXComponents: TfrxIBXComponents;

 

constructor TfrxIBXComponents.Create(AOwner: TComponent);

begin

inherited;

FOldComponents := IBXComponents;

IBXComponents := Self;

end;

 

destructor TfrxIBXComponents.Destroy;

begin

if IBXComponents = Self then

   IBXComponents := FOldComponents;

inherited;

end;

 

function TfrxIBXComponents.GetDescription: String;

begin

Result := 'IBX';

end;

 

Мы определяем глобальную переменную IBXComponents, которая будет ссылаться на экземпляр компонента TfrxIBXComponents. На случай, если вы несколько раз поместили компонент в проект (хотя это и не имеет смысла), предусмотрено сохранение ссылки на предыдущий компонент и восстановление ее после удаления компонента.

 

В свойство DefaultDatabase можно поместить ссылку на уже имеющееся в проекте подключение к БД. Мы напишем компоненты TfrxIBXTable, TfrxIBXQuery таким образом, чтобы они могли использовать это подключение по умолчанию (собственно, ради этого нам нужна глобальная переменная IBXComponents).

 

Следующий компонент - TfrxIBXDatabase. Он представляет собой обертку над TIBDatabase.

 

TfrxIBXDatabase = class(TfrxCustomDatabase)

private

   FDatabase: TIBDatabase;

   FTransaction: TIBTransaction;

   function GetSQLDialect: Integer;

   procedure SetSQLDialect(const Value: Integer);

protected

   procedure SetConnected(Value: Boolean); override;

   procedure SetDatabaseName(const Value: String); override;

   procedure SetLoginPrompt(Value: Boolean); override;

   procedure SetParams(Value: TStrings); override;

   function GetConnected: Boolean; override;

   function GetDatabaseName: String; override;

   function GetLoginPrompt: Boolean; override;

   function GetParams: TStrings; override;

public

   constructor Create(AOwner: TComponent); override;

   destructor Destroy; override;

   class function GetDescription: String; override;

   procedure SetLogin(const Login, Password: String); override;

   property Database: TIBDatabase read FDatabase;

published

   { определяем свойства, имеющиеся у TIBDatabase. Обратите внимание, что многие св-ва уже есть в родительском классе. }

   property DatabaseName;

   property LoginPrompt;

   property Params;

   property SQLDialect: Integer read GetSQLDialect write SetSQLDialect;

   { свойство Connected надо располагать последним! }

   property Connected;

end;

 

 

constructor TfrxIBXDatabase.Create(AOwner: TComponent);

begin

inherited;

{ создаем компонент - подключение }

FDatabase := TIBDatabase.Create(nil);

{ создаем компонент - транзакцию (специфика IBX) }

FTransaction := TIBTransaction.Create(nil);

FDatabase.DefaultTransaction := FTransaction;

{ не забудьте эту строку! }

Component := FDatabase;

end;

 

destructor TfrxIBXDatabase.Destroy;

begin

{ удаляем транзакцию }

FTransaction.Free;

{ а подключение удалится автоматически в родительском классе }

inherited;

end;

 

{ описание компонента - оно будет показано рядом с иконкой в панели объектов }

class function TfrxIBXDatabase.GetDescription: String;

begin

Result := 'IBX Database';

end;

 

{ перенаправляем свойства компонента на свойства обертки и наоборот }

function TfrxIBXDatabase.GetConnected: Boolean;

begin

Result := FDatabase.Connected;

end;

 

function TfrxIBXDatabase.GetDatabaseName: String;

begin

Result := FDatabase.DatabaseName;

end;

 

function TfrxIBXDatabase.GetLoginPrompt: Boolean;

begin

Result := FDatabase.LoginPrompt;

end;

 

function TfrxIBXDatabase.GetParams: TStrings;

begin

Result := FDatabase.Params;

end;

 

function TfrxIBXDatabase.GetSQLDialect: Integer;

begin

Result := FDatabase.SQLDialect;

end;

 

procedure TfrxIBXDatabase.SetConnected(Value: Boolean);

begin

FDatabase.Connected := Value;

FTransaction.Active := Value;

end;

 

procedure TfrxIBXDatabase.SetDatabaseName(const Value: String);

begin

FDatabase.DatabaseName := Value;

end;

 

procedure TfrxIBXDatabase.SetLoginPrompt(Value: Boolean);

begin

FDatabase.LoginPrompt := Value;

end;

 

procedure TfrxIBXDatabase.SetParams(Value: TStrings);

begin

FDatabase.Params := Value;

end;

 

procedure TfrxIBXDatabase.SetSQLDialect(const Value: Integer);

begin

FDatabase.SQLDialect := Value;

end;

 

{ этот метод нужен для работы с мастером подключения к БД }

procedure TfrxIBXDatabase.SetLogin(const Login, Password: String);

begin

Params.Text := 'user_name=' + Login + #13#10 + 'password=' + Password;

end;

 

 

Как видим, ничего сложного. Мы создаем объект FDatabase: TIBDatabase, и определяем свойства, которые мы хотели бы видеть в дизайнере. Для каждого свойства пишутся методы Get и Set. Аналогично поступаем с остальными классами, которые также являются обертками над соответствующими компонентами БД.

 

Следующий класс - TfrxIBXTable. Он, как говорилось выше, наследуется от стандартного класса TfrxCustomDataSet. Вся базовая функциональность (работа со списком полей, базовыми свойствами) уже реализована в базовом классе. Нам необходимо определить только те свойства, которые являются специфичными для данного компонента. Также необходимо перекрыть методы SetMaster, SetMasterFields для работы механизма master-detail.

 

TfrxIBXTable = class(TfrxCustomTable)

private

   FDatabase: TfrxIBXDatabase;

   FTable: TIBTable;

   procedure SetDatabase(const Value: TfrxIBXDatabase);

protected

   procedure Notification(AComponent: TComponent; Operation: TOperation); override;

   procedure SetMaster(const Value: TDataSource); override;

   procedure SetMasterFields(const Value: String); override;

   procedure SetIndexFieldNames(const Value: String); override;

   procedure SetIndexName(const Value: String); override;

   procedure SetTableName(const Value: String); override;

   function GetIndexFieldNames: String; override;

   function GetIndexName: String; override;

   function GetTableName: String; override;

public

   constructor Create(AOwner: TComponent); override;

   constructor DesignCreate(AOwner: TComponent; Flags: Word); override;

   class function GetDescription: String; override;

   procedure BeforeStartReport; override;

   property Table: TIBTable read FTable;

published

   property Database: TfrxIBXDatabase read FDatabase write SetDatabase;

end;

 

constructor TfrxIBXTable.Create(AOwner: TComponent);

begin

{ создаем компонент - таблицу }

FTable := TIBTable.Create(nil);

{ присваиваем ссылку на него свойству DataSet из базового класса - не забудьте эту строку! }

DataSet := FTable;

{ присваиваем ссылку на подключение к БД по умолчанию }

SetDatabase(nil);

{ после этого можно вызывать базовый конструктор }

inherited;

end;

 

{ этот конструктор вызывается в момент, когда вы добавляете компонент в отчет. Он автоматически подключает таблицу к компоненту TfrxIBXDatabase, если он уже есть. }

constructor TfrxIBXTable.DesignCreate(AOwner: TComponent; Flags: Word);

var

i: Integer;

l: TList;

begin

inherited;

l := Report.AllObjects;

for i := 0 to l.Count - 1 do

   if TObject(l[i]) is TfrxIBXDatabase then

   begin

     SetDatabase(TfrxIBXDatabase(l[i]));

     break;

   end;

end;

 

class function TfrxIBXTable.GetDescription: String;

begin

Result := 'IBX Table';

end;

 

{ отслеживаем удаление компонента TfrxIBXDatabase, на который мы ссылаемся в св-ве FDatabase. Иначе можем получить ошибку. }

procedure TfrxIBXTable.Notification(AComponent: TComponent; Operation: TOperation);

begin

inherited;

if (Operation = opRemove) and (AComponent = FDatabase) then

   SetDatabase(nil);

end;

 

procedure TfrxIBXTable.SetDatabase(const Value: TfrxIBXDatabase);

begin

{ обратите внимание - свойство Database типа TfrxIBXDatabase, а не TIBDatabase! }

FDatabase := Value;

{ если значение <> nil, подключаем таблицу к выбранному компоненту }

if Value <> nil then

   FTable.Database := Value.Database

{ иначе пробуем подключить к БД по умолчанию, определенной в компоненте TfrxIBXComponents }

else if IBXComponents <> nil then

   FTable.Database := IBXComponents.DefaultDatabase

{ если по каким-то причинам TfrxIBXComponents не существует, сбрасываем в nil }

else

   FTable.Database := nil;

{ если подключились успешно, надо установить флаг DBConnected }

DBConnected := FTable.Database <> nil;

end;

 

function TfrxIBXTable.GetIndexFieldNames: String;

begin

Result := FTable.IndexFieldNames;

end;

 

function TfrxIBXTable.GetIndexName: String;

begin

Result := FTable.IndexName;

end;

 

function TfrxIBXTable.GetTableName: String;

begin

Result := FTable.TableName;

end;

 

procedure TfrxIBXTable.SetIndexFieldNames(const Value: String);

begin

FTable.IndexFieldNames := Value;

end;

 

procedure TfrxIBXTable.SetIndexName(const Value: String);

begin

FTable.IndexName := Value;

end;

 

procedure TfrxIBXTable.SetTableName(const Value: String);

begin

FTable.TableName := Value;

end;

 

procedure TfrxIBXTable.SetMaster(const Value: TDataSource);

begin

FTable.MasterSource := Value;

end;

 

procedure TfrxIBXTable.SetMasterFields(const Value: String);

begin

FTable.MasterFields := Value;

FTable.IndexFieldNames := Value;

end;

 

{ этот метод необходим в некоторых случаях }

procedure TfrxIBXTable.BeforeStartReport;

begin

SetDatabase(FDatabase);

end;

 

Наконец, последний компонент - TfrxIBXQuery. Он наследуется от базового класса TfrxCustomQuery, в котором уже определены все необходимые свойства. Нам остается только определить свойство Database и перекрыть метод SetMaster (SetMasterFields в случае с Query перекрывать не надо). Реализация остальных методов аналогична компоненту TfrxIBXTable.

 

TfrxIBXQuery = class(TfrxCustomQuery)

private

   FDatabase: TfrxIBXDatabase;

   FQuery: TIBQuery;

   procedure SetDatabase(const Value: TfrxIBXDatabase);

protected

   procedure Notification(AComponent: TComponent; Operation: TOperation); override;

   procedure SetMaster(const Value: TDataSource); override;

   procedure SetSQL(Value: TStrings); override;

   function GetSQL: TStrings; override;

public

   constructor Create(AOwner: TComponent); override;

   constructor DesignCreate(AOwner: TComponent; Flags: Word); override;

   class function GetDescription: String; override;

   procedure BeforeStartReport; override;

   procedure UpdateParams; override;

   property Query: TIBQuery read FQuery;

published

   property Database: TfrxIBXDatabase read FDatabase write SetDatabase;

end;

 

constructor TfrxIBXQuery.Create(AOwner: TComponent);

begin

{ создаем компонент - запрос }

FQuery := TIBQuery.Create(nil);

{ присваиваем ссылку на него свойству DataSet из базового класса - не забудьте эту строку! }

Dataset := FQuery;

{ присваиваем ссылку на подключение к БД по умолчанию }

SetDatabase(nil);

{ после этого можно вызывать базовый конструктор }

inherited;

end;

 

constructor TfrxIBXQuery.DesignCreate(AOwner: TComponent; Flags: Word);

var

i: Integer;

l: TList;

begin

inherited;

l := Report.AllObjects;

for i := 0 to l.Count - 1 do

   if TObject(l[i]) is TfrxIBXDatabase then

   begin

     SetDatabase(TfrxIBXDatabase(l[i]));

     break;

   end;

end;

 

class function TfrxIBXQuery.GetDescription: String;

begin

Result := 'IBX Query';

end;

 

procedure TfrxIBXQuery.Notification(AComponent: TComponent; Operation: TOperation);

begin

inherited;

if (Operation = opRemove) and (AComponent = FDatabase) then

   SetDatabase(nil);

end;

 

procedure TfrxIBXQuery.SetDatabase(const Value: TfrxIBXDatabase);

begin

FDatabase := Value;

if Value <> nil then

   FQuery.Database := Value.Database

else if IBXComponents <> nil then

   FQuery.Database := IBXComponents.DefaultDatabase

else

   FQuery.Database := nil;

DBConnected := FQuery.Database <> nil;

end;

 

procedure TfrxIBXQuery.SetMaster(const Value: TDataSource);

begin

FQuery.DataSource := Value;

end;

 

function TfrxIBXQuery.GetSQL: TStrings;

begin

Result := FQuery.SQL;

end;

 

procedure TfrxIBXQuery.SetSQL(Value: TStrings);

begin

FQuery.SQL := Value;

end;

 

procedure TfrxIBXQuery.UpdateParams;

begin

{ в этом методе необходимо присвоить значения из Params в FQuery.Params }

{ это делается стандартной процедурой }

frxParamsToTParams(Self, FQuery.Params);

end;

 

procedure TfrxIBXQuery.BeforeStartReport;

begin

SetDatabase(FDatabase);

end;

 

 

Регистрация всех компонент движка выполняется в секции initialization.

 

initialization

{ вместо картинок используем индексы стандартных картинок 37,38,39 }

frxObjects.RegisterObject1(TfrxIBXDataBase, nil, '', '', 0, 37);

frxObjects.RegisterObject1(TfrxIBXTable, nil, '', '', 0, 38);

frxObjects.RegisterObject1(TfrxIBXQuery, nil, '', '', 0, 39);

 

finalization

CatBmp.Free;

frxObjects.Unregister(TfrxIBXDataBase);

frxObjects.Unregister(TfrxIBXTable);

frxObjects.Unregister(TfrxIBXQuery);

 

end.

 

 

Этого достаточно для того, чтобы использовать движок в отчетах. Осталось две вещи: зарегистрировать классы движка в скриптовой системе для того, чтобы к ним можно было обращаться из скрипта, и зарегистрировать редакторы некоторых свойств (например, TfrxIBXTable.TableName), чтобы с компонентом было удобно работать.

 

Код регистрации движка в скриптовой системе лучше вынести в отдельный файл с суффиксом RTTI. Подробнее о регистрации классов в скриптовой системе можно прочитать в соответствующей главе. Вот пример такого файла:

 

unit frxIBXRTTI;

 

interface

 

{$I frx.inc}

 

implementation

 

uses

Windows, Classes, fs_iinterpreter, frxIBXComponents

{$IFDEF Delphi6}

, Variants

{$ENDIF}; 

 

type

TFunctions = class(TfsRTTIModule)

public

   constructor Create(AScript: TfsScript); override;

end;

 

 

{ TFunctions }

 

constructor TFunctions.Create;

begin

inherited Create(AScript);

with AScript do

begin

   AddClass(TfrxIBXDatabase, 'TfrxComponent');

   AddClass(TfrxIBXTable, 'TfrxCustomDataset');

   AddClass(TfrxIBXQuery, 'TfrxCustomQuery');

end;

end;

 

initialization

fsRTTIModules.Add(TFunctions);

 

end.

 

 

Код редакторов свойств также лучше поместить в отдельный файл с суффиксом Editor. В нашем случае надо написать редакторы для свойств TfrxIBXDatabase.DatabaseName, TfrxIBXTable.IndexName, TfrxIBXTable.TableName. Подробнее о написании редакторов свойств можно прочитать в соответствующей главе. Вот пример такого файла:

 

unit frxIBXEditor;

 

interface

 

{$I frx.inc}

 

implementation

 

uses

Windows, Classes, SysUtils, Forms, Dialogs, frxIBXComponents, frxCustomDB,

frxDsgnIntf, frxRes, IBDatabase, IBTable

{$IFDEF Delphi6}

, Variants

{$ENDIF};

 

type

TfrxDatabaseNameProperty = class(TfrxStringProperty)

public

   function GetAttributes: TfrxPropertyAttributes; override;

   function Edit: Boolean; override;

end;

 

TfrxTableNameProperty = class(TfrxStringProperty)

public

   function GetAttributes: TfrxPropertyAttributes; override;

   procedure GetValues; override;

end;

 

TfrxIndexNameProperty = class(TfrxStringProperty)

public

   function GetAttributes: TfrxPropertyAttributes; override;

   procedure GetValues; override;

end;

 

 

{ TfrxDatabaseNameProperty }

 

function TfrxDatabaseNameProperty.GetAttributes: TfrxPropertyAttributes;

begin

{ это свойство имеет редактор }

Result := [paDialog];

end;

 

function TfrxDatabaseNameProperty.Edit: Boolean;

var

SaveConnected: Bool;

db: TIBDatabase;

begin

{ получаем ссылку на TfrxIBXDatabase.Database }

db := TfrxIBXDatabase(Component).Database;

{ создаем стандартный OpenDialog }

with TOpenDialog.Create(nil) do

begin

   InitialDir := GetCurrentDir;

   { нас интересуют файлы *.gdb }

   Filter := frxResources.Get('ftDB') + ' (*.gdb)|*.gdb|' + frxResources.Get('ftAllFiles') + ' (*.*)|*.*';

   Result := Execute;

   if Result then

   begin

     SaveConnected := db.Connected;

     db.Connected := False;

     { если диалог завершен успешно, присваиваем новое имя БД }

     db.DatabaseName := FileName;

     db.Connected := SaveConnected;

   end;

   Free;

end;

end;

 

 

{ TfrxTableNameProperty }

 

function TfrxTableNameProperty.GetAttributes: TfrxPropertyAttributes;

begin

{ свойство представляет собой список значений }

Result := [paMultiSelect, paValueList];

end;

 

procedure TfrxTableNameProperty.GetValues;

var

t: TIBTable;

begin

inherited;

{ получаем ссылку на компонент TIBTable }

t := TfrxIBXTable(Component).Table;

{ заполняем список доступных таблиц }

if t.Database <> nil then

   t.DataBase.GetTableNames(Values, False);

end;

 

 

{ TfrxIndexProperty }

 

function TfrxIndexNameProperty.GetAttributes: TfrxPropertyAttributes;

begin

{ свойство представляет собой список значений }

Result := [paMultiSelect, paValueList];

end;

 

procedure TfrxIndexNameProperty.GetValues;

var

i: Integer;

begin

inherited;

try

   { получаем ссылку на компонент TIBTable }

   with TfrxIBXTable(Component).Table do

     if (TableName <> '') and (IndexDefs <> nil) then

     begin

       { обновляем индексы }

       IndexDefs.Update;

       { заполняем список доступных индексов }

       for i := 0 to IndexDefs.Count - 1 do

         if IndexDefs[i].Name <> '' then

           Values.Add(IndexDefs[i].Name);

     end;

except

end;

end;

 

 

initialization

frxPropertyEditors.Register(TypeInfo(String), TfrxIBXDataBase, 'DatabaseName', TfrxDataBaseNameProperty);

frxPropertyEditors.Register(TypeInfo(String), TfrxIBXTable, 'TableName', TfrxTableNameProperty);

frxPropertyEditors.Register(TypeInfo(String), TfrxIBXTable, 'IndexName', TfrxIndexNameProperty);

 

end.