DevExpress.cx VirtualVerticalGrid как средство редактирование и отображения данных таблицы БД
Кузан Дмитрий
Добрый день!
В этом посте пойдет речь, о небольшой полезняшке позволяющий превратить стандартный DevExpress-овский компонент cxVirtualVerticalGrid в средство отображения и редактирования данных таблицы БД.
Предыстория:Мне очень импонирует представления данных таблиц БД в виде так сказать вертикального списка, разворачивающегося по подразделам. Что бы-было понятно о чем пойдет разговор представлю фрагмент скриншота из реально существующе программы, в нижней части он и представлен:
В общем захотелось мне такой список, да вот беда в стандартной DevExpress поставке такого компонента (который представлял DB-данные одной записи нет). Есть стандартный cxDbVerticalGrid но он не умеет предоставлять только 1 запись на просмотр, а предоставляет весь датасет, что согласитесь для моего случая не совсем то что нужно, т.к. он аналог грида только вертикальный. Мне же нужно было только видеть данные текущей записи (та которая в фокусе). Некий похожий компонент по функциональности компонент был в пакете InfoPower Professional, но ставить его я не хотел.
И тут мой взгляд упал на cxVirtualVerticalGrid который позволяет отображать собственные данные из класса наследника TcxCustomDataSource.
В общем пришлось написать посредника между cxVirtualVerticalGrid и datasource БД. Задача стояла так, что бы по колонке делался запрос к БД и выводилось значение в строку cxVirtualVerticalGrid связанного с полем БД. Ну и обратный процесс изменения данных в cxVirtualVerticalGrid-е попадал в БД. Этакий бонус - редактор полей БД, хоть и усеченный.
Вообщем поколдовав денек тродилась такое решение, в виде класса TBrokerDataSource:
001
unit _Class.BrokerDB;
006
Classes, cxCustomData, Variants, DB, DBCtrls;
010
TBrokerField = class(TCollectionItem)
013
procedure SetFieldName(const Value: String);
016
Property FieldName : String read FFieldName write SetFieldName;
019
TBrokerFieldList = class(TCollection)
021
function GetItems(Index: Integer): TBrokerField;
022
procedure SetItems(Index: Integer; const Value: TBrokerField);
024
Function Add: TBrokerField;
025
property Items[Index: Integer]: TBrokerField read GetItems write SetItems; default;
028
TBrokerDataSource = class(TcxCustomDataSource)
031
FBrokerFieldList : TBrokerFieldList;
032
FDataSource : TDataSource;
033
procedure SetBrokerFieldList(const Value: TBrokerFieldList);
035
procedure SetDataSource(const Value: TDataSource);
036
function GetDataSource: TDataSource;
037
Procedure DataChange(Sender: TObject; Field: TField);
039
function GetRecordCount: Integer; override;
040
function AppendRecord: TcxDataRecordHandle; override;
041
procedure DeleteRecord(ARecordHandle: TcxDataRecordHandle); override;
042
function GetValue(ARecordHandle: TcxDataRecordHandle;
043
AItemHandle: TcxDataItemHandle): Variant; override;
044
function InsertRecord(ARecordHandle: TcxDataRecordHandle): TcxDataRecordHandle; override;
045
procedure SetValue(ARecordHandle: TcxDataRecordHandle;
046
AItemHandle: TcxDataItemHandle; const AValue: Variant); override;
049
destructor Destroy; override;
050
property Modified: boolean read FModified;
052
Property DataSource: TDataSource Read GetDataSource Write SetDataSource;
053
property Fields : TBrokerFieldList read FBrokerFieldList write SetBrokerFieldList;
059
{ TCustomDataSource }
060
constructor TBrokerDataSource.Create;
062
FBrokerFieldList := TBrokerFieldList.Create(TBrokerField);
065
destructor TBrokerDataSource.Destroy;
067
FBrokerFieldList.Free;
071
//------------------------------------------------------------------------------
072
function TBrokerDataSource.GetRecordCount: Integer;
077
function TBrokerDataSource.GetValue(ARecordHandle: TcxDataRecordHandle;
078
AItemHandle: TcxDataItemHandle): Variant;
084
Result := '<Нет данных>';
085
if Assigned(DataSource) then
087
if Assigned(DataSource.DataSet) then
089
I := Integer(AItemHandle);
090
if I < FBrokerFieldList.Count then
092
FN := FBrokerFieldList[I].FieldName;
093
Result := DataSource.DataSet.FieldByName(FN).AsVariant;
099
procedure TBrokerDataSource.SetValue(ARecordHandle: TcxDataRecordHandle;
100
AItemHandle: TcxDataItemHandle;
101
const AValue: Variant);
106
I := Integer(AItemHandle);
107
if I < FBrokerFieldList.Count then
109
if Assigned(DataSource.DataSet) then
111
FN := FBrokerFieldList[I].FieldName;
112
if not DataSource.DataSet.Modified then
113
DataSource.DataSet.Edit;
114
DataSource.DataSet.FieldByName(FN).AsVariant := AValue;
115
DataSource.DataSet.Post;
121
function TBrokerDataSource.AppendRecord: TcxDataRecordHandle;
123
// AStatElement: TStatElement;
125
// AStatElement := TStatElement.Create;
126
// Result := TcxDataRecordHandle(FStatElementList.Add(AStatElement));
128
// if not Modified then
129
// FModified := True;
132
function TBrokerDataSource.InsertRecord(ARecordHandle: TcxDataRecordHandle): TcxDataRecordHandle;
134
// AStatElement: TStatElement;
136
// AStatElement := TStatElement.Create;
137
// FStatElementList.Insert(Integer(ARecordHandle), AStatElement);
138
// Result := TcxDataRecordHandle(ARecordHandle);
140
// if not Modified then
141
// FModified := True;
144
procedure TBrokerDataSource.DataChange(Sender: TObject; Field: TField);
149
procedure TBrokerDataSource.DeleteRecord(
150
ARecordHandle: TcxDataRecordHandle);
157
procedure TBrokerDataSource.SetBrokerFieldList(const Value: TBrokerFieldList);
159
FBrokerFieldList := Value;
162
function TBrokerDataSource.GetDataSource: TDataSource;
164
Result := FDataSource;
167
procedure TBrokerDataSource.SetDataSource(const Value: TDataSource);
169
FDataSource := Value;
170
FDataSource.OnDataChange := DataChange;
174
procedure TBrokerField.SetFieldName(const Value: String);
180
function TBrokerFieldList.Add: TBrokerField;
182
Result := TBrokerField(inherited Add);
185
function TBrokerFieldList.GetItems(Index: Integer): TBrokerField;
187
Result := TBrokerField(inherited GetItem(Index))
190
procedure TBrokerFieldList.SetItems(Index: Integer; const Value: TBrokerField);
192
inherited SetItem(Index, Value);
Использовать его просто
объявляете переменну класса в нужном месте
1
Broker : TBrokerDataSource;
далее связываете cxVirtualVerticalGrid c данным брокером и БД
1
Broker.DataSource := <DataSource талицы БД>;
2
cxVirtualVerticalGrid.DataController.CustomDataSource := Broker;
после чего заполняете отображаемые колонки в cxVirtualVerticalGrid-е
с помощью функции AddFieldBroker, в которую передаете поле БД для отображения
сама процедура
01
procedure AddFieldBroker(var VirtualVerticalGrid: TcxVirtualVerticalGrid;
02
var DataSourceBroker : TBrokerDataSource;
03
RowParent : TcxCustomRow;
06
BrField : TBrokerField;
08
BrField:= DataSourceBroker.Fields.Add;
09
BrField.FieldName := Field.FieldName;
10
with VirtualVerticalGrid do
12
with AddChild(RowParent, TcxEditorRow) as TcxEditorRow do
14
Properties.Caption := Field.DisplayName;
15
Properties.HeaderAlignmentHorz := taLeftJustify;
16
case Field.DataType of
18
Properties.DataBinding.ValueTypeClass := TcxBooleanValueType;
19
ftDate, ftDateTime, ftTime
21
Properties.DataBinding.ValueTypeClass := TcxDateTimeValueType;
22
ftFloat,ftExtended,ftSingle :
23
Properties.DataBinding.ValueTypeClass := TcxFloatValueType;
25
Properties.DataBinding.ValueTypeClass := TcxFMTBcdValueType;
26
ftInteger, ftAutoInc, ftShortint
28
Properties.DataBinding.ValueTypeClass := TcxIntegerValueType;
29
ftLargeint,ftLongWord :
30
Properties.DataBinding.ValueTypeClass := TcxLargeIntValueType;
32
Properties.DataBinding.ValueTypeClass := TcxObjectValueType;
34
Properties.DataBinding.ValueTypeClass := TcxSmallintValueType;
35
ftTimeStamp, ftOraTimeStamp :
36
Properties.DataBinding.ValueTypeClass := TcxSQLTimeStampValueType;
38
Properties.DataBinding.ValueTypeClass := TcxVariantValueType;
40
Properties.DataBinding.ValueTypeClass := TcxWideStringValueType;
41
ftString, ftFixedChar :
42
Properties.DataBinding.ValueTypeClass := TcxStringValueType;
44
Properties.DataBinding.ValueTypeClass := TcxCurrencyValueType;
46
Properties.DataBinding.ValueTypeClass := TcxWordValueType;
Пример заполнения представлен ниже (взято с реального проекта)
05
Broker := TBrokerDataSource.Create;
06
Broker.DataSource := DsContract;
07
cxVirtualVerticalGrid.DataController.CustomDataSource := Broker;
10
with cxVirtualVerticalGrid do
12
Row := Add(TcxCategoryRow);
13
TcxCategoryRow(Row).Properties.Caption := 'Данные регистрации';
16
// поля - строки вcxVirtualVerticalGrid
17
AddFieldBroker(cxVirtualVerticalGrid, Broker, Row, ContractNUM_REGISTRATION);
18
AddFieldBroker(cxVirtualVerticalGrid, Broker, Row, ContractDATE_REGISTRATION);
19
AddFieldBroker(cxVirtualVerticalGrid, Broker, Row, ContractUSER_NAME);
И вуаля - готово, можно пользоватся
Ссылки по теме