Here my latest addition to GridView, a virtual column that asks for data through an Event when it's painted. It also features editing ans calls an event when there is new virtual data.
For this it has to store the Row/Column Index inside each cell as i did not find a 'normal' way to retrieve a cells coordinates (Boki?).
It's not integrated with the columns editor as i could not find documentation on it. So usage is:
CODE
procedure TForm1.DoGetText(Sender: TObject; const ACol, ARow: Integer; var Value: WideString);
begin
Value := Format('R%dC%d', [ARow, ACol]);
OutputDebugString(PChar(Format('DoGetText(%d,%d,%s)', [ACol, ARow, Value])));
end;
procedure TForm1.DoSetText(Sender: TObject; const ACol, ARow: Integer;
const Value: WideString);
begin
OutputDebugString(PChar(Format('DoSetText(%d,%d,%s)', [ACol, ARow, Value])));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
vc : TVirtualColumn;
begin
vc := GridView1.Columns.Add(TVirtualColumn, 'test') as TVirtualColumn;
vc.OnGetText := DoGetText;
vc.OnSetText := DoSetText;
vc.Options := vc.Options + [coEditing];
GridView1.AddRow(5);
begin
Value := Format('R%dC%d', [ARow, ACol]);
OutputDebugString(PChar(Format('DoGetText(%d,%d,%s)', [ACol, ARow, Value])));
end;
procedure TForm1.DoSetText(Sender: TObject; const ACol, ARow: Integer;
const Value: WideString);
begin
OutputDebugString(PChar(Format('DoSetText(%d,%d,%s)', [ACol, ARow, Value])));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
vc : TVirtualColumn;
begin
vc := GridView1.Columns.Add(TVirtualColumn, 'test') as TVirtualColumn;
vc.OnGetText := DoGetText;
vc.OnSetText := DoSetText;
vc.Options := vc.Options + [coEditing];
GridView1.AddRow(5);
end;
It adds 5 rows and populates them with row/column numbers.
The first part is the VirtualColumn. It only supports Textual Display because formatting in my opinion is something for the supplier with this kind of virtual data. Save the following as VirtualColumn.pas:
CODE
unit VirtualColumn;
interface
uses
Classes, CellEditors, Columns, ColumnClasses, Displays, Cells;
type
TGetTextEvent = procedure(Sender: TObject; const ACol, ARow: Integer; var Value: WideString) of object;
TSetTextEvent = procedure(Sender: TObject; const ACol, ARow: Integer; const Value: WideString) of object;
TVirtualCell = class(TCell)
private
FCol,
FRow: Integer;
FOnGetText: TGetTextEvent;
FOnSetText: TSetTextEvent;
protected
function GetAsBoolean: Boolean; override;
function GetAsDateTime: TDateTime; override;
function GetAsFloat: Double; override;
function GetAsInteger: Integer; override;
function GetAsString: WideString; override;
procedure SetAsBoolean(const Value: Boolean); override;
procedure SetAsDateTime(const Value: TDateTime); override;
procedure SetAsFloat(const Value: Double); override;
procedure SetAsInteger(const Value: Integer); override;
procedure SetAsString(const Value: WideString); override;
public
constructor Create(Cells: TCells; Column: TCustomColumn; ACol, ARow: Integer); reintroduce;
end;
TVirtualColumn = class(TTextualColumn)
private
{ Private declarations }
FTextAfter: WideString;
FTextBefore: WideString;
FAutoExecute: Boolean;
FOnGetText: TGetTextEvent;
FOnSetText: TSetTextEvent;
procedure SetAutoExecute(const Value: Boolean);
procedure SetTextAfter(const Value: WideString);
procedure SetTextBefore(const Value: WideString);
protected
{ Protected declarations }
function GetColumnDisplayClass: TColumnDisplayClass; override;
public
{ Public declarations }
procedure Assign(Source: TPersistent); override;
constructor Create(AOwner: TComponent); override;
function GetDisplayText(Value: WideString): WideString; override;
function IsKeyValid(Key: Char): Boolean; override;
function GetCellEditorClass: TCellEditorClass; override;
procedure DoGetText(Sender: TObject; const ACol, ARow: Integer; var Value: WideString);
procedure DoSetText(Sender: TObject; const ACol, ARow: Integer; const Value: WideString);
published
{ Published declarations }
property AutoExecute: Boolean read FAutoExecute write SetAutoExecute;
property OnGetText: TGetTextEvent read FOnGetText write FOnGetText;
property OnSetText: TSetTextEvent read FOnSetText write FOnSetText;
property TextAfter: WideString read FTextAfter write SetTextAfter;
property TextBefore: WideString read FTextBefore write SetTextBefore;
end;
TVirtualColumnDisplay = class(TTextualColumnDisplay)
procedure Paint; override;
public
constructor Create(AColumn: TCustomColumn); override;
end;
implementation
uses
GridView, SysUtils;
{ TVirtualColumn }
procedure TVirtualColumn.Assign(Source: TPersistent);
begin
inherited;
if Source is TVirtualColumn then
begin
AutoExecute := TVirtualColumn(Source).AutoExecute;
TextAfter := TVirtualColumn(Source).TextAfter;
TextBefore := TVirtualColumn(Source).TextBefore;
end;
end;
constructor TVirtualColumn.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FAutoExecute := False;
FTextAfter := '';
FTextBefore := '';
DefaultValue := '';
Options := Options + [coShowTextFitHint];
SetSortType(stAlphabetic);
SetColumnType(ctVirtual);
end;
procedure TVirtualColumn.SetAutoExecute(const Value: Boolean);
begin
FAutoExecute := Value;
end;
procedure TVirtualColumn.SetTextAfter(const Value: WideString);
begin
FTextAfter := Value;
end;
procedure TVirtualColumn.SetTextBefore(const Value: WideString);
begin
FTextBefore := Value;
end;
function TVirtualColumn.GetCellEditorClass: TCellEditorClass;
begin
Result := TTextualEditor;
end;
function TVirtualColumn.GetDisplayText(Value: WideString): WideString;
begin
Result := FTextAfter + Value + FTextBefore;
end;
function TVirtualColumn.IsKeyValid(Key: Char): Boolean;
begin
Result := Ord(Key) > 32;
end;
function TVirtualColumn.GetColumnDisplayClass: TColumnDisplayClass;
begin
Result := TVirtualColumnDisplay;
end;
procedure TVirtualColumn.DoGetText(Sender: TObject; const ACol, ARow: Integer; var Value: WideString);
begin
if Assigned(FOnGetText) then
FOnGetText(Sender, ACol, ARow, Value)
else
Value := 'n/a';
end;
procedure TVirtualColumn.DoSetText(Sender: TObject; const ACol, ARow: Integer; const Value: WideString);
begin
if Assigned(FOnSetText) then
FOnSetText(Sender, ACol, ARow, Value)
//else
// Value := 'n/a';
end;
{ TVirtualColumnDisplay }
constructor TVirtualColumnDisplay.Create(AColumn: TCustomColumn);
begin
inherited;
end;
procedure TVirtualColumnDisplay.Paint;
begin
with Column as TVirtualColumn do
DrawTextRect(TextBefore + AsString + TextAfter, GetTextRect);
end;
{ TVirtualCell }
constructor TVirtualCell.Create(Cells: TCells; Column: TCustomColumn; ACol, ARow: Integer);
begin
FCol := ACol;
FRow := ARow;
FOnGetText := TVirtualColumn(Column).DoGetText;
FOnSetText := TVirtualColumn(Column).DoSetText;
inherited Create(Cells);
end;
function TVirtualCell.GetAsBoolean: Boolean;
begin
Result := StrToBool(GetAsString);
end;
function TVirtualCell.GetAsDateTime: TDateTime;
begin
Result := StrToDateTime(GetAsString);
end;
function TVirtualCell.GetAsFloat: Double;
begin
Result := StrToFloat(GetAsString);
end;
function TVirtualCell.GetAsInteger: Integer;
begin
Result := StrToInt(GetAsString);
end;
function TVirtualCell.GetAsString: WideString;
begin
FOnGetText(Self, FCol, FRow, Result)
end;
procedure TVirtualCell.SetAsBoolean(const Value: Boolean);
begin
SetAsString(BoolToStr(Value, True));
inherited;
end;
procedure TVirtualCell.SetAsDateTime(const Value: TDateTime);
begin
SetAsString(DateTimeToStr(Value));
inherited;
end;
procedure TVirtualCell.SetAsFloat(const Value: Double);
begin
SetAsString(FloatToStr(Value));
inherited;
end;
procedure TVirtualCell.SetAsInteger(const Value: Integer);
begin
SetAsString(IntToStr(Value));
inherited;
end;
procedure TVirtualCell.SetAsString(const Value: WideString);
begin
FOnSetText(Self, FCol, FRow, Value);
inherited;
end;
end.
interface
uses
Classes, CellEditors, Columns, ColumnClasses, Displays, Cells;
type
TGetTextEvent = procedure(Sender: TObject; const ACol, ARow: Integer; var Value: WideString) of object;
TSetTextEvent = procedure(Sender: TObject; const ACol, ARow: Integer; const Value: WideString) of object;
TVirtualCell = class(TCell)
private
FCol,
FRow: Integer;
FOnGetText: TGetTextEvent;
FOnSetText: TSetTextEvent;
protected
function GetAsBoolean: Boolean; override;
function GetAsDateTime: TDateTime; override;
function GetAsFloat: Double; override;
function GetAsInteger: Integer; override;
function GetAsString: WideString; override;
procedure SetAsBoolean(const Value: Boolean); override;
procedure SetAsDateTime(const Value: TDateTime); override;
procedure SetAsFloat(const Value: Double); override;
procedure SetAsInteger(const Value: Integer); override;
procedure SetAsString(const Value: WideString); override;
public
constructor Create(Cells: TCells; Column: TCustomColumn; ACol, ARow: Integer); reintroduce;
end;
TVirtualColumn = class(TTextualColumn)
private
{ Private declarations }
FTextAfter: WideString;
FTextBefore: WideString;
FAutoExecute: Boolean;
FOnGetText: TGetTextEvent;
FOnSetText: TSetTextEvent;
procedure SetAutoExecute(const Value: Boolean);
procedure SetTextAfter(const Value: WideString);
procedure SetTextBefore(const Value: WideString);
protected
{ Protected declarations }
function GetColumnDisplayClass: TColumnDisplayClass; override;
public
{ Public declarations }
procedure Assign(Source: TPersistent); override;
constructor Create(AOwner: TComponent); override;
function GetDisplayText(Value: WideString): WideString; override;
function IsKeyValid(Key: Char): Boolean; override;
function GetCellEditorClass: TCellEditorClass; override;
procedure DoGetText(Sender: TObject; const ACol, ARow: Integer; var Value: WideString);
procedure DoSetText(Sender: TObject; const ACol, ARow: Integer; const Value: WideString);
published
{ Published declarations }
property AutoExecute: Boolean read FAutoExecute write SetAutoExecute;
property OnGetText: TGetTextEvent read FOnGetText write FOnGetText;
property OnSetText: TSetTextEvent read FOnSetText write FOnSetText;
property TextAfter: WideString read FTextAfter write SetTextAfter;
property TextBefore: WideString read FTextBefore write SetTextBefore;
end;
TVirtualColumnDisplay = class(TTextualColumnDisplay)
procedure Paint; override;
public
constructor Create(AColumn: TCustomColumn); override;
end;
implementation
uses
GridView, SysUtils;
{ TVirtualColumn }
procedure TVirtualColumn.Assign(Source: TPersistent);
begin
inherited;
if Source is TVirtualColumn then
begin
AutoExecute := TVirtualColumn(Source).AutoExecute;
TextAfter := TVirtualColumn(Source).TextAfter;
TextBefore := TVirtualColumn(Source).TextBefore;
end;
end;
constructor TVirtualColumn.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FAutoExecute := False;
FTextAfter := '';
FTextBefore := '';
DefaultValue := '';
Options := Options + [coShowTextFitHint];
SetSortType(stAlphabetic);
SetColumnType(ctVirtual);
end;
procedure TVirtualColumn.SetAutoExecute(const Value: Boolean);
begin
FAutoExecute := Value;
end;
procedure TVirtualColumn.SetTextAfter(const Value: WideString);
begin
FTextAfter := Value;
end;
procedure TVirtualColumn.SetTextBefore(const Value: WideString);
begin
FTextBefore := Value;
end;
function TVirtualColumn.GetCellEditorClass: TCellEditorClass;
begin
Result := TTextualEditor;
end;
function TVirtualColumn.GetDisplayText(Value: WideString): WideString;
begin
Result := FTextAfter + Value + FTextBefore;
end;
function TVirtualColumn.IsKeyValid(Key: Char): Boolean;
begin
Result := Ord(Key) > 32;
end;
function TVirtualColumn.GetColumnDisplayClass: TColumnDisplayClass;
begin
Result := TVirtualColumnDisplay;
end;
procedure TVirtualColumn.DoGetText(Sender: TObject; const ACol, ARow: Integer; var Value: WideString);
begin
if Assigned(FOnGetText) then
FOnGetText(Sender, ACol, ARow, Value)
else
Value := 'n/a';
end;
procedure TVirtualColumn.DoSetText(Sender: TObject; const ACol, ARow: Integer; const Value: WideString);
begin
if Assigned(FOnSetText) then
FOnSetText(Sender, ACol, ARow, Value)
//else
// Value := 'n/a';
end;
{ TVirtualColumnDisplay }
constructor TVirtualColumnDisplay.Create(AColumn: TCustomColumn);
begin
inherited;
end;
procedure TVirtualColumnDisplay.Paint;
begin
with Column as TVirtualColumn do
DrawTextRect(TextBefore + AsString + TextAfter, GetTextRect);
end;
{ TVirtualCell }
constructor TVirtualCell.Create(Cells: TCells; Column: TCustomColumn; ACol, ARow: Integer);
begin
FCol := ACol;
FRow := ARow;
FOnGetText := TVirtualColumn(Column).DoGetText;
FOnSetText := TVirtualColumn(Column).DoSetText;
inherited Create(Cells);
end;
function TVirtualCell.GetAsBoolean: Boolean;
begin
Result := StrToBool(GetAsString);
end;
function TVirtualCell.GetAsDateTime: TDateTime;
begin
Result := StrToDateTime(GetAsString);
end;
function TVirtualCell.GetAsFloat: Double;
begin
Result := StrToFloat(GetAsString);
end;
function TVirtualCell.GetAsInteger: Integer;
begin
Result := StrToInt(GetAsString);
end;
function TVirtualCell.GetAsString: WideString;
begin
FOnGetText(Self, FCol, FRow, Result)
end;
procedure TVirtualCell.SetAsBoolean(const Value: Boolean);
begin
SetAsString(BoolToStr(Value, True));
inherited;
end;
procedure TVirtualCell.SetAsDateTime(const Value: TDateTime);
begin
SetAsString(DateTimeToStr(Value));
inherited;
end;
procedure TVirtualCell.SetAsFloat(const Value: Double);
begin
SetAsString(FloatToStr(Value));
inherited;
end;
procedure TVirtualCell.SetAsInteger(const Value: Integer);
begin
SetAsString(IntToStr(Value));
inherited;
end;
procedure TVirtualCell.SetAsString(const Value: WideString);
begin
FOnSetText(Self, FCol, FRow, Value);
inherited;
end;
end.
Then a number of changes the the GridView suite.
1) In columns.pas add ctVirtual to TColumnType
CODE
TColumnType = (ctAutoInc, ctNone, ctGraphic, ctBoolean, ctDate, ctFloat, ctInteger, ctString, ctLookup, ctVirtual);
and include VirtualColumn to the implementation uses Clause.
2) in Cells.pas add the following to the case statement in TCells.AddRow:
CODE
ctVirtual: ACell := TVirtualCell.Create(Self, FColumns[i], i, FRowCount);
3) In GridView.pas add to DrawCellData:
CODE
ctVirtual: Display.AsString := Cell[ACol, ARow].AsString;
and include VirtualColumn to the implementation uses Clause.
and add TVirtualColumn in RegisterColumnsIntoDesigner:
CODE
RegisterClasses([TGraphicColumn, TCheckBoxColumn, TDateColumn, THtmlColumn,
TImageColumn, TComboBoxColumn, TNumericColumn, TProgressColumn, TRateColumn,
TTextualColumn, TVirtualColumn]);
TImageColumn, TComboBoxColumn, TNumericColumn, TProgressColumn, TRateColumn,
TTextualColumn, TVirtualColumn]);
That should be all.
As usual, it's fresh code so there might be a bug. Reports are welcome (and i hope Boki puts in into GridView off-course).
[/code]











