Во фреймворке ONTARIO1 при разработке форм клиентского приложения необходимо использовать следующие компоненты закладки ONTARIO:
Табл.4.1.
Тип отображаемых данных | Компонент Delphi | Примечание |
Строки до 255 символов | TDBOMaskEdit | Форматы масок отображения совпадают с форматами TMaskEdit |
Числа и денежные величины | TCurrencyEdit | Форматы масок отображения совпадают с форматами TMaskEdit |
Дата | TDateEdit | |
Объект БД | TDBOField | |
Таблицы, включающие в себя объекты БД | TDBODrawGrid, TDBObjGrid |
TDBODrawGrid (только для отображения), TDBObjGrid (отображение и редактирование) |
Все компоненты связи с БД являются встроенными процедурами (TStoredProc), настраиваемыми на компонент TDatabase главной формы dbOntario и работающими через это единое соединение. Компоненты TStoredProc должны быть в неактивном состоянии, а их инициализация единообразно описывается в переопределяемом методе InitDataEnvironment (см пример ниже для spTDBODoc_View).
Компонент отображает объект БД с названием и пиктограммой. Для инициализации компонента используется ключевое свойство Value, содержащее текущий идентификатор объекта БД (OID). Например:
procedure TfrmDBODocEdit.InitDataEnvironment(
DBOInfo: TDBOInfo );
begin
inherited;
spTDBODoc_View.Active := false;
spTDBODoc_View.ParamByName( '@OID' ).Value := DBOInfo.OID;
spTDBODoc_View.Open;
edtState.Value := spTDBODoc_View.FieldByName( 'StateID' ).AsInteger;
edtStateDate.Date := spTDBODoc_View.FieldByName( 'LastStateDate' ).AsDatetime;
edtUser.Value := spTDBODoc_View.FieldByName( 'CreatorID' ).AsInteger;
edtStore.Value := spTDBODoc_View.FieldByName( 'StoreID' ).AsInteger;
edtWhere.Value := spTDBODoc_View.FieldByName( 'WhereID' ).AsInteger;
edtDate.Date := DBOInfo.CreationDate;
edtNo.Text := DBOInfo.Ext;
end;
В данном примере, кроме инициализации компонента edtState, показано также применение содержания информационной структуры DBOInfo, присущей каждой форме, унаследованной от TfrmBaseDialog и каждому классу, унаследованному от TDBObject.
CanSelect: boolean
SFolderName: string
Разрешает или запрещает выбор объекта из всплывающего диалогового окна поддерева объектов БД. При этом минимально допустимый класс объекта необходимо занести в свойство
DBOClass, а название системной папки, в которую попадает пользователь при выборе из диалогового окна объекта, в SFolderName. Если он не указан, то выбор начинается с корневой вершины системы. Подробнее о системных папках написано в руководстве по разработке модуля.DBOInfo: TDBOInfo
Структура содержит базовую информацию об объекте, содержащемся в поле в данный момент времени. Структура описана в DBOConst.pas.
SetFieldByOID( OID: variant )
Аналогичен по действию простому присваиванию идентификатора объекта свойству
Value, но может принимать значения типа Variant. Используется во избежание ошибки инициализации, если заранее неизвестен тип инициализирующего значения.OnChangeDBO
Происходит, если пользователь изменил содержимое компонента. При редактировании должен настраиваться на процедуру
edtNameChange или вызывать ее в своем обработчике.OnSelectDBO
Происходит при выборе объекта БД, из появляющегося диалогового окна поддерева объектов. Корень поддерева определяется свойством
SFolderName. Передает в качестве параметра DBOInfo выбранного объекта.Не используется в формах, является суперклассом для TDBObjGrid, реализующим его базовые возможности.
Компонент отображает таблицу, которая может включать в себя одну или более колонок, содержащих объекты БД с пиктограммой. В runtime позволяет по нажатию правой кнопки мыши на ячейке объекта получить список его интерфейсных методов в контекстном всплывающем меню.
TDBObjGrid как потомок TDBGrid, имеет источник данных TDataSource, который, в свою очередь должен быть связан с компонентом TStoredProc, непосредственно заполняющим таблицу данными выборкой из БД. Если Grid предполагает редактирование, необходимо добавить к заполняющей его TStoredProc связанный компонент TSQLUpdate (пустой, без SQL–операторов), а ее свойство CachedUpdates установить в true.
CanDelete: boolean
Разрешает/запрещает удаление строк в
Grid по нажатию Ctrl+Del.CanInsert: boolean
Разрешает/запрещает добавление строк в
Grid по нажатию Ctrl+Ins.CanChoice: boolean
Разрешает/запрещает вызов диалогового окна поддерева выбора объекта после нажатия
Ctrl+Ins.DBOClass: string
Определяет минимально допустимый класс добавляемого по
Ctrl+Ins объекта. По умолчанию это TDBObject.LogActions[ i ]
: integerИндексированное свойство доступа к типу
i–го действия над строками DataSet данного Grid, зарегистрированного в журнале.LogItems
Число записей в журнале действий над строками
Grid и записями DataSet соответственно. Записи в журнале нумеруются от 0 до LogItems-1.LogOIDs[ i ]
: integerИндексированное свойство доступа к
OID по i–му действию над строками DataSet данного Grid, зарегистрированному в журнале.SFolderName: string
Определяет корень поддерева (системную папку) диалогового окна выбора объекта.
ShowClassIcons: boolean
Разрешает/запрещает вывод пиктограммы класса объекта БД.
AddDBOCellInfo( <OID_Column_Name>, <BaseClass_Column_Name>, <DBOName_Column_Name>, <SFolder_Name> )
Заносит в Grid информацию об именах информативных колонок таблицы выборки (TDataSet), возвращаемой процедурой. Здесь:
<OID_Column_Name> – имя поля (колонки), содержащей идентификаторы объектов БД (OID);
<BaseClass_Column_Name> – имя поля, содержащего наименование класса объекта БД;
<DBOName_Column_Name> – имя поля, содержащего наименование объекта БД;
<SFolder_Name> – имя системной папки, на которую будет установлено поддерево выбора объекта БД при изменении содержимого ячейки. Заполнение этого параметра автоматически позволит по двойному щелчку мыши на ячейке с объектом БД вызывать диалог выбора объекта.
AddLogAction( <OID>, <Action_Mode> )
Добавляет в журнал операций (действий над содержимым Grid) информацию о произведенном действии.
<OID> – первичный ключ записи в DataSet данного Grid;
<Action_Mode> – вид действий над содержанием Grid. Является одной из констант: DBG_INSERTED, DBG_CHANGED, DBG_CHANGED (при добавлении, модификации и удалении записи соответственно)
ClearLogAction
Очищает содержимое журнала действий.
OnDBOCellEdit( Sender: TObject )
Происходит при редактировании ячейки с объектом БД (при двойном щелчке мыши).
OnDeleteDBO( Sender: TObject )
Происходит при удалении строки из
DataSet по нажатию Ctrl+Del, если удаление разрешено в CanDelete.OnHeaderDblClick(Column: TColumn)
Происходит при двойном щелчке мыши на заголовке колонки. Колонка передается в качестве параметра.
OnInsertDBO( Sender: TObject )
Происходит при добавлении строки в
DataSet по нажатию Ctrl+Ins, если удаление разрешено в CanInsert.OnSelectCellDBO( Sender: TObject; DBOInfo: TDBOInfo )
Происходит после выбора объекта из поддерева в диалоговом окне при редактировании ячейки, содержащей объект БД.
DBOInfo содержит информацию о выбранном объекте.OnSelectlDBO( Sender: TObject; DBOInfo: TDBOInfo )
Происходит после выбора объекта из поддерева в диалоговом окне при добавлении строки в
DataSet по Ctrl+Ins. DBOInfo содержит информацию о выбранном объекте.OnSelectObject
Происходит при выборе объекта из окна Проводника. Используется в общесистемных формах.
В качестве примера прокомментируем разработку формы редактирования комплекта TfrmDBOSetEdit (файл SetEdit.pas).
unit SetEdit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ThngEdit, DB, DBTables, StdCtrls, Mask, DBOMask, Buttons, DBOBtn, Grids,
DBGrids, DBODrGrd, DBOGrid, DBOConst, ExtCtrls, DBCtrls;
type
TfrmDBOSetEdit = class(TfrmDBOThingEdit)
dsrcGoods: TDataSource;
spTDBOSet_ViewContents: TStoredProc;
UpdateSQL1: TUpdateSQL;
spTDBOSet_InclObj: TStoredProc;
dbgGoods: TDBObjGrid;
spTDBOSet_ExclObj: TStoredProc;
spTDBOGood_View: TStoredProc;
spTDBObject_View: TStoredProc;
procedure spTDBOSet_ViewContentsAfterPost(DataSet: TDataSet);
procedure dbgGoodsSelectDBO(Sender: TObject; DBOInfo: TDBOInfo);
procedure dbgGoodsDeleteDBO(Sender: TObject);
procedure dbgGoodsSelectCellDBO(Sender: TObject; DBOInfo: TDBOInfo);
private
{ Private declarations }
public
{ Public declarations }
procedure InitDataEnvironment( DBOInfo: TDBOInfo ); override;
function ValidCheck: boolean; override;
procedure SaveDataEnvironment; override;
end;
var
frmDBOSetEdit: TfrmDBOSetEdit;
implementation
{$R *.DFM}
procedure TfrmDBOSetEdit.InitDataEnvironment( DBOInfo: TDBOInfo );
var
i: integer;
Part : integer;
begin
inherited;
dbgGoods.AddDBOCellInfo( 'OID', 'BaseClass', 'Name', '' );
dbgGoods.AddDBOCellInfo( 'MeasureID', 'MeasureClass', 'MeasureName', 'MeasureSec'
);
spTDBOSet_ViewContents.Active := false;
spTDBOSet_ViewContents.ParamByName( '@OID' ).AsInteger := DBOInfo.OID;
spTDBOSet_ViewContents.Open;
with dbgGoods do begin
ReadOnly := false;
Columns.State := csCustomized;
Part := round( Width / 15 );
for i := Columns.Count - 1 downto 0 do begin
if ( Columns.Items[ i ].FieldName = 'Name' ) then begin
Columns.Items[ i ].Title.Caption :=
'Позиция';
Columns.Items[ i ].Width := Part * 5;
Columns.Items[ i ].ReadOnly := true;
end
else
if ( Columns.Items[ i ].FieldName = 'Amount' )
then begin
Columns.Items[ i ].Title.Caption :=
'Количество';
Columns.Items[ i ].Width := Part *
3;
Columns.Items[ i ].Alignment :=
taLeftJustify;
Columns.Items[ i ].ReadOnly :=
false;
( Columns.Items[ i ].Field as
TFloatField ).DisplayFormat := '###,###,###.######';
( Columns.Items[ i ].Field as
TFloatField ).EditFormat :=
DisplayToEditFormat( ( Columns.Items[ i ].Field as TFloatField ).DisplayFormat );
end
else
if ( Columns.Items[ i ].FieldName =
'MeasureName' ) then begin
Columns.Items[ i
].Title.Caption := 'Измерение';
Columns.Items[ i
].Width := Part * 4;
Columns.Items[ i
].ReadOnly := true;
end
else
if ( Columns.Items[ i
].FieldName = 'No' ) then begin
Columns.Items[ i ].Title.Caption := 'N п/п';
Columns.Items[ i ].Width := Part * 2;
Columns.Items[ i ].ReadOnly := false;
end
else
Columns.Items[ i ].Destroy;
end;
end;
end;
function TfrmDBOSetEdit.ValidCheck: boolean;
begin
Result := inherited ValidCheck;
if spTDBOSet_ViewContents.RecordCount <= 0 then
raise Exception.Create( 'Необходимо внести хотя
бы одну позицию в комплект' );
end;
procedure TfrmDBOSetEdit.SaveDataEnvironment;
var
i: integer;
begin
inherited;
// включение/исключение из комплекта
for i := 0 to dbgGoods.LogItems - 1 do begin
case dbgGoods.LogActions[ i ] of
DBG_INSERTED,
DBG_CHANGED:
begin
spTDBOSet_InclObj.Active := false;
spTDBOSet_InclObj.ParamByName( '@SetID'
).AsInteger := DBOInfo.OID;
spTDBOSet_InclObj.ParamByName( '@OID'
).AsInteger := dbgGoods.LogOIDs[ i ];
spTDBOSet_InclObj.ParamByName( '@No' ).AsFloat
:=
spTDBOSet_ViewContents.Lookup( 'OID',
dbgGoods.LogOIDs[ i ], 'No' );
spTDBOSet_InclObj.ParamByName( '@Amount'
).AsFloat :=
spTDBOSet_ViewContents.Lookup( 'OID',
dbgGoods.LogOIDs[ i ], 'Amount' );
spTDBOSet_InclObj.ParamByName( '@MeasureID'
).AsInteger :=
spTDBOSet_ViewContents.Lookup( 'OID',
dbgGoods.LogOIDs[ i ], 'MeasureID' );
spTDBOSet_InclObj.ExecProc;
end;
DBG_DELETED:
begin
spTDBOSet_ExclObj.Active := false;
spTDBOSet_ExclObj.ParamByName( '@SetID'
).AsInteger := DBOInfo.OID;
spTDBOSet_ExclObj.ParamByName( '@OID'
).AsInteger := dbgGoods.LogOIDs[ i ];
spTDBOSet_ExclObj.ExecProc;
end;
else ;
end;
end;
dbgGoods.ClearLogAction;
end;
procedure TfrmDBOSetEdit.spTDBOSet_ViewContentsAfterPost(DataSet: TDataSet);
begin
inherited;
dbgGoods.AddLogAction( DataSet.FieldByName( 'OID' ).AsInteger, DBG_CHANGED );
end;
procedure TfrmDBOSetEdit.dbgGoodsSelectDBO(Sender: TObject; DBOInfo: TDBOInfo);
var
MaxNo, MeasureID: integer;
begin
inherited;
if spTDBOSet_ViewContents.Locate( 'OID', DBOInfo.OID, [] ) then begin
MessageDlg( 'Позиция уже включена в список:' +
#13 +
'<' + DBOInfo.Name + '>',
mtError, [ mbOK ], 0 );
end
else begin
spTDBOGood_View.Active := false;
spTDBOGood_View.ParamByName( '@OID' ).Value := DBOInfo.OID;
spTDBOGood_View.Open;
if spTDBOGood_View.RecordCount > 0 then begin
MeasureID := spTDBOGood_View.FieldByName( 'MeasureID'
).AsInteger;
end
else begin
MeasureID := 0;
end;
spTDBObject_View.Active := false;
spTDBObject_View.ParamByName( '@OID' ).Value := MeasureID;
spTDBObject_View.Open;
// определение максимального номера
MaxNo := 1;
spTDBOSet_ViewContents.First;
while not spTDBOSet_ViewContents.EOF do begin
if spTDBOSet_ViewContents.FieldByName( 'No' ).AsInteger
>= MaxNo then
MaxNo := spTDBOSet_ViewContents.FieldByName( 'No'
).AsInteger + 1;
spTDBOSet_ViewContents.Next;
end;
spTDBOSet_ViewContents.Append;
spTDBOSet_ViewContents.FieldByName( 'No' ).AsInteger := MaxNo;
spTDBOSet_ViewContents.FieldByName( 'OID' ).AsInteger := DBOInfo.OID;
spTDBOSet_ViewContents.FieldByName( 'Name' ).AsString := DBOInfo.Name;
spTDBOSet_ViewContents.FieldByName( 'BaseClass' ).AsString :=
DBOInfo.BaseClass;
spTDBOSet_ViewContents.FieldByName( 'Amount' ).Value := 1;
spTDBOSet_ViewContents.FieldByName( 'MeasureID' ).Value := MeasureID;
spTDBOSet_ViewContents.FieldByName( 'MeasureName' ).Value :=
spTDBObject_View.FieldByName( 'Name' ).Value;
spTDBOSet_ViewContents.FieldByName( 'MeasureClass' ).Value :=
spTDBObject_View.FieldByName( 'BaseClass' ).Value;
spTDBOSet_ViewContents.Post;
dbgGoods.AddLogAction( DBOInfo.OID, DBG_INSERTED );
end;
end;
procedure TfrmDBOSetEdit.dbgGoodsDeleteDBO(Sender: TObject);
begin
inherited;
if spTDBOSet_ViewContents.RecordCount > 0 then begin
dbgGoods.AddLogAction( spTDBOSet_ViewContents.FieldByName( 'OID'
).AsInteger, DBG_DELETED );
spTDBOSet_ViewContents.Delete;
DataChanged := true;
end
end;
procedure TfrmDBOSetEdit.dbgGoodsSelectCellDBO(Sender: TObject; DBOInfo: TDBOInfo);
begin
inherited;
spTDBOSet_ViewContents.Edit;
spTDBOSet_ViewContents.FieldByName( 'MeasureID' ).Value := DBOInfo.OID;
spTDBOSet_ViewContents.FieldByName( 'MeasureName' ).Value := DBOInfo.Name;
spTDBOSet_ViewContents.FieldByName( 'MeasureClass' ).Value := DBOInfo.BaseClass;
spTDBOSet_ViewContents.Post;
end;
end.
В разделе объявления объектов формы определен компонент dbgGoods класса TDBObjGrid отображающий позиции, входящие в комплект. Через DataSource его заполняет spTDBOSet_GetGoods, которая является редактируемым DataSet и связана с компонентом SQLUpdate1. Напомним, что свойство CachedUpdates установлено в true. Тексты серверных процедур можно просмотреть в файле \SERVER\Things\Set.sql. Приведем процедуру просмотра позиций, входящих в комплект:
CREATE PROCEDURE TDBOSet_ViewContents
@OID int
as
SELECT Set2Obj.No,
OID = Set2Obj.OID,
Name = Objs.Name,
BaseClass = Objs.BaseClass,
Set2Obj.Amount,
Set2Obj.MeasureID,
MeasureName = ( SELECT Name FROM Objs
WHERE OID = Set2Obj.MeasureID ),
MeasureClass = ( SELECT BaseClass FROM
Objs WHERE OID = Set2Obj.MeasureID )
FROM Set2Obj, Objs ( NOLOCK )
WHERE Objs.OID = Set2Obj.OID AND
Set2Obj.SetID = @OID
ORDER BY Set2Obj.No
GO
В методе инициализации формы InitDataEnvironment определяются ячейки для отображения объектов БД в Grid
dbgGoods.AddDBOCellInfo( 'GoodID', 'BaseClass',
'Name', '' );
dbgGoods.AddDBOCellInfo( 'MeasureID', 'MeasureClass', 'MeasureName', 'Measure' );
Первая колонка ячеек содержит объекты класса товаров, входящих в комплект, а вторая ячейка отображает единицы измерения и является редактируемой, поскольку имеет информацию о системной папке “
Measure”, предположительно содержащей объекты класса единиц измерения.После открытия
DataSet процедуры TDBOSet_GetGoods описывается инициализация самого Grid с детализацией информации по колонкам. Таким образом отображаются только нужные колонки, которым при необходимости прописываются свойства возможности редактирования, выравнивания и ширины. Ширина подбирается простым образом: вся ширина Grid делится на N частей из которых N-1 распределяется между колонками.В методе проверки
ValidCheck происходит стандартная проверка на наличие хотя бы одной позиции в комплекте.Далее следует метод
SaveDataEnvironment, производящий анализ журнала действий со строками DataSet. В конце необходимо очистить журнал действий во избежание недоразумений при предварительном сохранении. Сами действия регистрируются в обработчиках событий добавления, удаления и модификации ниже по тексту:OnAfterPost – для регистрации модификации записи (DBG_CHANGED);
OnSelectDBO – для занесения новой записи в DataSet, заполнения ее атрибутами выбранного объекта (товара) и регистрации действия (DBG_INSERTED);
OnDeleteDBO – для удаления записи из DataSet и регистрации действия (DBG_DELETED);
OnSelectCellDBO – для заполнения информации о единице измерения по товару и регистрации изменения в журнале.