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);
И вуаля - готово, можно пользоватся
Ссылки по теме