Delphi 3. Библиотека программиста

       

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


Тем временем Мститель снова погрузился в чтение похищенного Дневника.

Дневник №16 (27 марта). В Delphi 1.0 совместное использование таблиц несколькими формами было крайне хлопотным делом. Хотя возможности не ограничивались размещением таблиц и источников данных на всех формах, работавших с данными, неуклюжее альтернативное решение требовало временного создания дополнительных источников данных с их последующим удалением. Мне часто хотелось отыскать более простой способ. В последую щих версиях Delphi появились объекты, которые назывались модулями данных и заметно упрощали эту задачу. Я решил побольше узнать о них.

Как выяснилось, модуль данных представляет собой специализированную форму, на которой можно разместить только стандартные объекты из палитры Data Access. В приложении можно построить целую базу данных, с таблицами, источниками, запросами и всем остальным— и разместить ее в одном модуле данных. Чтобы результатами трудов могли воспользоваться другие формы, необходимо включить модуль данных в их секции implementation (не в секции interface!). При этом компоненты и поля модуля данных становятся доступными для компонентов формы, связанных с данными (а также для самого инспектора объектов).

Я решил создать простой пример с данными одного из моих клиентов, фирмы «Чичен-Итца Пицца». Данные хранятся в виде таблицы Paradox, в файле PIZADAT.DB. Таблица состоит из трех полей: название, цена продажи и себестоимость лучших продуктов фирмы. Я решил добавить вычисляемое поле для отображения прибыли по каждой позиции (в процентах).

Рис. 15.6. Модуль данных в режиме конструирования

Сначала я создал (для последующего использования в свойстве DatabaseName) псевдоним с именем Pizza, определяющий каталог с таблицей. Затем создал новый модуль данных и присвоил ему имя PizzaData. В этот модуль (см. рис. 15.6) я поместил таблицу и источник данных, присвоив им имена ProductTable и ProductSource соответственно. Я подключил ProductSource
к ProductTable и задал свойству AutoEdit значение False. Затем открыл для таблицы Fields Editor и добавил в него все возможные поля. Наконец, я создал новое вычисляемое поле для хранения процента прибыли и написал обработ чик события OnCalcFields таблицы ProductTable. Окно модуля данных показано на рис. 15.6. Исходный текст модуля PizzaData приведен в листинге 15.4.

Листинг 15.4. Исходный текст модуля данных

{——————————} {Демонстрация работы с модулями данных } {PIZADAT.PAS : Модуль данных } {Автор: Эйс Брейкпойнт, N.T.P. } {При содействии Дона Тейлора } { } { Модуль данных содержит простейшую комбинацию } { таблица/источник данных,подключаемую к таблице} { Paradox. Для пользователей модуля создано } { вычисляемое поле. } { } { Написано для *High Performance Delphi 3 } Programming* } { Copyright (c) 1997 The Coriolis Group, Inc.} { Дата последней редакции 23/4/97 } {—————————} unit PizaDat; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, DB, DBTables;

type TPizzaData = class(TDataModule) ProductTable: TTable; ProductSource: TDataSource; ProductTableName: TStringField; ProductTablePrice: TCurrencyField; ProductTableCost: TCurrencyField; ProductTablePctProfit: TFloatField; procedure ProductTableCalcFields(DataSet: TDataSet); private { Private declarations } public { Public declarations } end; var PizzaData: TPizzaData; implementation {$R *.DFM} procedure TPizzaData.ProductTableCalcFields (DataSet: TDataSet); begin ProductTablePctProfit.Value := 100.0 * ((ProductTablePrice.Value - ProductTableCost.Value) / ProductTableCost.Value); end; end.

С данными все понятно. Настало время писать демонстрационную
программу. Я решил поиграть с двумя формами. Первая форма просто обращается к данным через источник, расположенный в модуле данных. Эта фор ма отображает имя продукта и вычисляемое поле. Я поместил на нее компонент-навигатор для перемещения по таблице.

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

На рис. 15.7 изображены обе формы во время работы. В листинге 15.5 приведен исходный текст главной формы, а в листинге 15.6 — исходный текст вспомогательной формы.

Рис. 15.7. Программа, демонстрирующая использование модуля данных

Листинг 15.5. Исходный текст главной формы

{——————————————————————————————————————————————————————} { Демонстрация работы с модулями данных } { PIZAMAIN.PAS : Главная форма } { Автор: Эйс Брейкпойнт, N.T.P. } { При содействии Дона Тейлора } { } { Демонстрационная программа показывает, как } { происходит подключение формы к модулю данных, } { созданному для данного проекта. Форма } { содержит переключатель для смены источника данных - } { модуль или локальная пара таблица/источник данных. } { } { Написано для *High Performance Delphi 3 Programming* } { Copyright (c) 1997 The Coriolis Group, Inc. } { Дата последней редакции 23/4/97 } {——————————————————————————————————————————————————————} unit PizaMain; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids, DBGrids, ExtCtrls, DBCtrls, DBTables, DB, StdCtrls; type TForm1 = class(TForm) DBGrid: TDBGrid; Navigator: TDBNavigator; DataSourceRBGroup: TRadioGroup; QuitBtn: TButton; LocalTable: TTable; LocalDataSource: TDataSource; LocalTableName: TStringField; LocalTablePrice: TCurrencyField; LocalTableCost: TCurrencyField; Bevel1: TBevel; procedure FormShow(Sender: TObject); procedure FormCreate(Sender: TObject); procedure DataSourceRBGroupClick(Sender: TObject); procedure QuitBtnClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation uses PizaDat, PizaFrm2; {$R *.DFM} procedure TForm1.FormShow(Sender: TObject); begin Form2.Show; end; procedure TForm1.FormCreate(Sender: TObject); begin DataSourceRBGroup.ItemIndex := 0; end; procedure TForm1.DataSourceRBGroupClick(Sender: TObject); begin if Tag > 0 then case DataSourceRBGroup.ItemIndex of 0 : begin DBGrid.DataSource := PizzaData.ProductSource; Navigator.DataSource := PizzaData.ProductSource; end; 1 : begin DBGrid.DataSource := LocalDataSource; Navigator.DataSource := LocalDataSource; end; end { case } else Tag := 1; end; procedure TForm1.QuitBtnClick(Sender: TObject); begin Close; end; end.

Листинг 15.6. Исходный текст вспомогательной формы

{——————————————————————————————————————————————————————} { Демонстрация работы с модулями данных } { PIZAFRM2.PAS : Вспомогательная форма } { Автор: Эйс Брейкпойнт, N.T.P. } { При содействии Дона Тейлора } { } { Демонстрационная программа показывает, как } { происходит подключение формы к модулю данных, } { включенному в проект. Эта форма получает данные } { из модуля данных проекта. } { } { Написано для *High Performance Delphi 3 Programming* } { Copyright (c) 1997 The Coriolis Group, Inc. } { Дата последней редакции 23/4/97 } {——————————————————————————————————————————————————————} unit PizaFrm2; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, DBCtrls, ExtCtrls, DB; type TForm2 = class(TForm) NameDBText: TDBText; PctDBText: TDBText; Label1: TLabel; Label2: TLabel; Navigator: TDBNavigator; Bevel1: TBevel; private { Private declarations } public { Public declarations } end; var Form2: TForm2; implementation uses PizaDat; {$R *.DFM} end.

Перед компиляцией я задаю свойствам Active всех объектов-таблиц значение True. Наверное, сказывается сила привычки.

В секциях implementation обеих форм указывается PizaDat (имя модуля данных). После этого поля модуля данных становятся доступными в инспекторе объектов для любого компонента, связанного с данными.

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

Похоже, обработчик OnClick для переключателей вызывается во время создания формы. К этому моменту источники данных еще не были полностью сконструированы и подключены, и в результате возникает исключение. Я решил предотвратить эту ситуацию с помощью свойства Tag формы. Во время инициализации оно равно 0, поэтому попытка подключения источников не производится. Однако следующий вызов обработчика — совсем другое дело, поскольку значение Tag было заменено на 1.

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

Разумеется, возможности модулей данных отнюдь не ограничиваются вычисляемыми полями. Ведь в конце концов модуль данных является полноценным модулем Object Pascal, который может содержать новые объекты и методы, а также обработчики для любых событий, связанных с таблицами, источниками данных, SQL-запросами и т.д. В сущности, программист может реализовать полный набор логических правил для работы с данными компании. Довольно круто — и открывает очень, очень широкие возможности.

Конец записи (27 марта).



Содержание раздела