The full code used to create a custom data source is listed below.
unit Unit1;
interface
uses
SysUtils, Types, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls,
cxCustomData, cxDataStorage, cxGrid, cxGridCustomTableView, cxGridTableView;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
FGrid: TcxGrid;
FTableView: TcxGridTableView;
procedure LoadValues();
public
property Grid: TcxGrid read FGrid;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
{ User Objects }
PListEntry = ^TListEntry;
TListEntry = packed record
Description: string;
OnHand: Integer;
Price: Currency;
end;
TPriceList = class
private
FRecords: TList;
public
constructor Create;
destructor Destroy; override;
procedure Add(ADescription: string; AOnHand: Integer;
APrice: Currency);
procedure Clear;
end;
TUserDataSource = class(TcxCustomDataSource)
private
FPriceList: TPriceList;
function GetDataBinding(AItemIndex: Integer):
TcxGridItemDataBinding;
protected
function GetInfoForCompare(ARecordHandle: TcxDataRecordHandle;
AItemHandle: TcxDataItemHandle; var PValueBuffer: PChar):
Boolean; override;
function GetItemHandle(AItemIndex: Integer): TcxDataItemHandle;
override;
function GetRecordCount: Integer; override;
function GetValue(ARecordHandle: TcxDataRecordHandle;AItemHandle:
TcxDataItemHandle): Variant; override;
function IsNativeCompare: Boolean; override;
public
constructor Create(APriceList: TPriceList);
end;
var
PriceList: TPriceList;
{ TPriceList }
constructor TPriceList.Create;
begin
FRecords := TList.Create;
end;
destructor TPriceList.Destroy;
begin
Clear;
FRecords.Free;
inherited Destroy;
end;
procedure TPriceList.Add(ADescription: string; AOnHand: Integer; APrice: Currency);
var
P: PListEntry;
begin
New(P);
FRecords.Add(P);
P^.Description := ADescription;
P^.OnHand := AOnHand;
P^.Price := APrice;
end;
procedure TPriceList.Clear;
begin
while FRecords.Count > 0 do
begin
Dispose(PListEntry(FRecords[FRecords.Count - 1]));
FRecords.Delete(FRecords.Count - 1);
end;
end;
{ TUserDataSource }
constructor TUserDataSource.Create(APriceList: TPriceList);
begin
inherited Create;
FPriceList := APriceList;
end;
function TUserDataSource.GetDataBinding(AItemIndex: Integer): TcxGridItemDataBinding;
begin
Result := TcxCustomGridTableItem(DataController.GetItem(AItemIndex)).DataBinding;
end;
function TUserDataSource.GetInfoForCompare(ARecordHandle: TcxDataRecordHandle;
AItemHandle: TcxDataItemHandle; var PValueBuffer: PChar): Boolean;
var
ADataBinding: TcxGridItemDataBinding;
begin
ADataBinding := TcxGridItemDataBinding(AItemHandle);
PValueBuffer := PChar(Integer(FPriceList.
FRecords[Integer(ARecordHandle)]) +
Integer(ADataBinding.Data));
Result := True;
end;
function TUserDataSource.GetItemHandle(AItemIndex: Integer): TcxDataItemHandle;
begin
Result := TcxDataItemHandle(GetDataBinding(AItemIndex));
end;
function TUserDataSource.GetRecordCount: Integer;
begin
Result := FPriceList.FRecords.Count;
end;
function TUserDataSource.GetValue(ARecordHandle: TcxDataRecordHandle; AItemHandle: TcxDataItemHandle): Variant;
var
P: PChar;
ADataBinding: TcxGridItemDataBinding;
begin
ADataBinding := TcxGridItemDataBinding(AItemHandle);
P := PChar(Integer(FPriceList.FRecords[Integer(ARecordHandle)]) +
Integer(ADataBinding.Data));
Result := ADataBinding.ValueTypeClass.GetValue(P);
end;
function TUserDataSource.IsNativeCompare: Boolean;
begin
Result := True;
end;
{ routines }
procedure GenerateColumns(AGridTableView: TcxGridTableView);
var
AListEntry: TListEntry;
begin
with AGridTableView do
begin
OptionsSelection.HideFocusRect := False;
OptionsSelection.MultiSelect := True;
ClearItems;
with CreateColumn as TcxGridColumn do
begin
Caption := 'Description';
DataBinding.ValueTypeClass := TcxStringValueType;
DataBinding.Data := Pointer(0);
Width := 100;
end;
with CreateColumn as TcxGridColumn do
begin
Caption := 'OnHand';
DataBinding.ValueTypeClass := TcxIntegerValueType;
DataBinding.Data := Pointer(Integer(@AListEntry.OnHand) -
Integer(@AListEntry));
Width := 100;
end;
with CreateColumn as TcxGridColumn do
begin
Caption := 'Price';
DataBinding.ValueTypeClass := TcxCurrencyValueType;
DataBinding.Data := Pointer(Integer(@AListEntry.Price) -
Integer(@AListEntry));
Width := 100;
end;
end;
end;
procedure TForm1.LoadValues();
begin
PriceList.Add('Dive kayak', 24, 3999.95);
PriceList.Add('Underwater Diver Vehicle', 5, 1680.00);
PriceList.Add('Regulator System', 165, 250.00);
PriceList.Add('Personal Dive Sonar', 46, 235.00);
PriceList.Add('Depth/Pressure Gauge', 128, 206.00);
FTableView.DataController.CustomDataSource.DataChanged;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FGrid := TcxGrid.Create(Self);
with FGrid do
begin
FTableView := CreateView(TcxGridTableView) as TcxGridTableView;
Levels.Add.GridView := FTableView;
GenerateColumns(FTableView);
FTableView.OptionsView.Footer := True;
with FTableView.DataController.Summary.FooterSummaryItems.Add do
begin
Kind := skCount;
ItemLink := FTableView.Columns[0];
end;
Align := alClient;
Parent := Self;
end;
FTableView.DataController.CustomDataSource :=
TUserDataSource.Create(PriceList);
LoadValues();
end;
initialization
PriceList := TPriceList.Create;
finalization
PriceList.Free;
end.
//Unit1.h
#ifndef Unit1H
#define Unit1H
//-------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include "cxgrid.hpp"
#include "cxGridTableView.hpp"
#include "cxCustomData.hpp"
//-------------------------------------
//User Objects
struct TListEntry {
String Description;
int OnHand;
Currency Price;
};
typedef ::TListEntry* PListEntry;
//-------------------------------------
class TPriceList
{
public:
TPriceList();
~TPriceList();
void Add(String ADescription, int AOnHand, Currency APrice);
void Clear();
TList *FRecords;
};
//-------------------------------------
class TUserDataSource : public TcxCustomDataSource
{
private:
TPriceList *FPriceList;
TcxGridItemDataBinding* GetDataBinding(int AItemIndex);
protected:
bool __fastcall GetInfoForCompare(void * ARecordHandle, void * AItemHandle, char * &PValueBuffer);
void* __fastcall GetItemHandle(int AItemIndex);
int __fastcall GetRecordCount();
Variant __fastcall GetValue(void * ARecordHandle, void * AItemHandle);
bool __fastcall IsNativeCompare();
public:
TUserDataSource(TPriceList *APriceList);
};
//-------------------------------------
class TForm1 : public TForm
{
__published:// IDE-managed Components
private: // User declarations
TcxGrid *FGrid;
TcxGridTableView *FTableView;
TPriceList *FPriceList;
void LoadValues();
public: // User declarations
__fastcall TForm1(TComponent* Owner);
__fastcall ~TForm1();
};
//-------------------------------------
extern PACKAGE TForm1 *Form1;
//-------------------------------------
#endif
//Unit1.cpp
//-------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//-------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//-------------------------------------
//Constants used for column identification
const
DescriptionID = 0,
OnHandID = 1,
PriceID = 2;
//-------------------------------------
// TPriceList
TPriceList::TPriceList()
{
FRecords = new TList;
}
TPriceList::~TPriceList()
{
Clear();
delete FRecords;
}
void TPriceList::Add(String ADescription, int AOnHand, Currency APrice)
{
::PListEntry P = new ::TListEntry;
FRecords->Add(P);
P->Description = ADescription;
P->OnHand = AOnHand;
P->Price = APrice;
}
void TPriceList::Clear()
{
while (FRecords->Count > 0)
{
delete FRecords->Items[FRecords->Count - 1];
FRecords->Delete(FRecords->Count - 1);
}
}
//-------------------------------------
//TUserDataSource
TUserDataSource::TUserDataSource(TPriceList *APriceList) : TcxCustomDataSource()
{
FPriceList = APriceList;
}
/*
Returns the TcxGridColumn.DataBinding property for a specified visible index of a column. This property is initialized when a grid column is created.
*/
TcxGridItemDataBinding* TUserDataSource::GetDataBinding(int AItemIndex)
{
return ((TcxCustomGridTableItem*)DataController->GetItem(AItemIndex))->DataBinding;
}
/*
Returns TcxGridColumn.DataBinding as an item handle for a specified visible index of a column
*/
void* __fastcall TUserDataSource::GetItemHandle(int AItemIndex)
{
return (TcxDataItemHandle*)GetDataBinding(AItemIndex);
}
/*
Returns a pointer to the memory address at which the value of the desired field resides. AItemHandle is an item handle retrieved by the GetItemHandle method.
*/
bool __fastcall TUserDataSource::GetInfoForCompare(void * ARecordHandle, void * AItemHandle, char * &PValueBuffer)
{
TcxGridItemDataBinding * ADataBinding = (TcxGridItemDataBinding*)AItemHandle;
int ARecordIndex = (int)ARecordHandle;
::PListEntry APEntry = (::PListEntry)(*FPriceList->FRecords)[ARecordIndex];
switch (int(ADataBinding->Data))
{
case DescriptionID:
PValueBuffer = (char*)&APEntry->Description;
break;
case OnHandID:
PValueBuffer = (char*)&APEntry->OnHand;
break;
case PriceID:
PValueBuffer = (char*)&APEntry->Price;
break;
}
return true;
}
/*
Returns the number of records to display in a grid control
*/
int __fastcall TUserDataSource::GetRecordCount()
{
return FPriceList->FRecords->Count;
}
/*
Returns a specific field value from the TListEntry object. ARecordHandle identifies a record in the list. AItemHandle is an item (column) handle retrieved by the GetItemHandle method.
*/
Variant __fastcall TUserDataSource::GetValue(void * ARecordHandle, void * AItemHandle)
{
TcxGridItemDataBinding *ADataBinding = (TcxGridItemDataBinding*)AItemHandle;
int ARecordIndex = (int)ARecordHandle;
::PListEntry APEntry = (::PListEntry)(*FPriceList->FRecords)[ARecordIndex];
switch (int(ADataBinding->Data))
{
case DescriptionID:
return APEntry->Description;
case OnHandID:
return APEntry->OnHand;
case PriceID:
return APEntry->Price;
}
}
/*
Since the TUserDataSource provides the GetInfoForCompare procedure, the IsNativeCompare function should return True.
*/
bool __fastcall TUserDataSource::IsNativeCompare()
{
return true;
}
//-------------------------------------
//Routines
void GenerateColumns(TcxGridTableView *AGridTableView)
{
TcxGridColumn *AColumn;
AGridTableView->OptionsSelection->HideFocusRect = false;
AGridTableView->OptionsSelection->MultiSelect = true;
AGridTableView->ClearItems();
AColumn = AGridTableView->CreateColumn();
AColumn->Caption = "Description";
AColumn->DataBinding->ValueTypeClass = __classid (TcxStringValueType);
AColumn->DataBinding->Data = (void*)DescriptionID;
AColumn->Width = 100;
AColumn = AGridTableView->CreateColumn();
AColumn->Caption = "OnHand";
AColumn->DataBinding->ValueTypeClass = __classid (TcxIntegerValueType);
AColumn->DataBinding->Data = (void*)OnHandID;
AColumn->Width = 100;
AColumn = AGridTableView->CreateColumn();
AColumn->Caption = "Price";
AColumn->DataBinding->ValueTypeClass = __classid (TcxCurrencyValueType);
AColumn->DataBinding->Data = (void*)PriceID;
AColumn->Width = 100;
}
//-------------------------------------
void TForm1::LoadValues()
{
FPriceList->Add("Dive kayak", 24, 3999.95);
FPriceList->Add("Underwater Diver Vehicle", 5, 1680.00);
FPriceList->Add("Regulator System", 165, 250.00);
FPriceList->Add("Personal Dive Sonar", 46, 235.00);
FPriceList->Add("Depth/Pressure Gauge", 128, 206.00);
FTableView->DataController->CustomDataSource->DataChanged();
}
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
FPriceList = new ::TPriceList();
FGrid = new TcxGrid(this);
FGrid->Align = alClient;
FGrid->Parent = this;
FTableView = (TcxGridTableView*)(FGrid->CreateView(__classid(TcxGridTableView)));
FGrid->Levels->Add()->GridView = FTableView;
GenerateColumns(FTableView);
FTableView->OptionsView->Footer = true;
TcxDataSummaryItem *AItem = FTableView->DataController->Summary->FooterSummaryItems->Add();
AItem->Kind = skCount;
AItem->ItemLink = FTableView->Columns[0];
FTableView->OptionsData->Appending = false;
FTableView->OptionsData->Inserting = false;
FTableView->DataController->CustomDataSource = new TUserDataSource(FPriceList);
LoadValues();
}
__fastcall TForm1::~TForm1() {
delete FPriceList;
}
//-------------------------------------