TAdvSpreadGrid : custom function libraries
TAdvSpreadGrid allows to use libraries that extend the built-in functions. A function library is a class that descends from TMathLib defined in the unit AdvPars. In order to be able to use multiple different function libraries simultaneously, a TLibBinder component can be assigned to TAdvSpreadGrid. Multiple TMathLib components can be assigned to the TLibBinder.Anatomy of TMathLib
TMathLib implements a number of public virtual functions that can be overridden to implement custom functions:
function HandlesFunction(FuncName:string):Boolean;
function HandlesStrFunction(FuncName:string):Boolean;
function CalcFunction(FuncName:string;Params:TParamList;var ErrType,ErrParam: Integer):Double;
function CalcStrFunction(FuncName:string;Params:TStringList;var ErrType,ErrParam: Integer):string;
function GetEditHint(FuncName:string;ParamIndex: Integer):string;
function HandlesStrFunction(FuncName:string):Boolean;
function CalcFunction(FuncName:string;Params:TParamList;var ErrType,ErrParam: Integer):Double;
function CalcStrFunction(FuncName:string;Params:TStringList;var ErrType,ErrParam: Integer):string;
function GetEditHint(FuncName:string;ParamIndex: Integer):string;
Implemented functions
The methods HandlesFunction and HandlesStrFunction are simple methods being called by the TLibBinder and assumed to return true when the library implements the function with the name 'FuncName'.Example
function TMiscMathLib.HandlesFunction(FuncName: string): boolean;
begin
Result := (FuncName = 'HARMEAN') or
(FuncName = 'GEOMEAN');
end;
begin
Result := (FuncName = 'HARMEAN') or
(FuncName = 'GEOMEAN');
end;
This shows a library implementing 2 statistical functions HARMEAN and GEOMEAN. HandlesFunction should return true for functions that return a floating point result type. If a library implements a function with a string result, the HandlesStrFunction should be used.
Function calculation
The method CalcFunction implements the actual calculation of the function. The first parameter is the function name that should be calculated, the second parameter is a list of function parameters. The 2 last parameters can be set if an incorrect parameter is specified and the index of this incorrect parameter.Example
function TMiscMathLib.CalcFunction(FuncName: string; Params: TParamList; var ErrType,ErrParam: Integer): Double; var k: Integer; d: Double; begin Result := 0.0; ErrType := Error_NoError; if FuncName = 'HARMEAN' then begin d := 0; for k := 1 to Params.Count do begin if Params.Items[k - 1] <> 0 then begin d := d + (1 / Params.Items[k - 1]); end else begin ErrType := Error_DivisionByZero; ErrParam := k - 1; end; Result := 1/d * Params.Count; end; Exit; end; if FuncName = 'GEOMEAN' then begin d := 1; for k := 1 to Params.Count do begin d := d * Params.Items[k - 1]; end; if Params.Count > 0 then begin Result := exp(1/Params.Count * ln(d)); end else begin ErrType := Error_DivisionByZero; ErrParam := 0; end; end; end;
In this example, the functions HARMEAN and GEOMEAN are implemented. This shows how the method loops through the number of parameters passed to the function and calculates the result. As shown here in the code, a parameter of these functions cannot be zero. If a zero parameter is found, the method sets the error type to Error_DivisionByZero and if needed the index of the parameter that caused the actual error. The supported types of errors are:
Error_NoError = 0;
Error_NoFormula = 1;
Error_DivisionByZero = 2;
Error_InvalidValue = 3;
Error_InvalidCellRef = 4;
Error_InvalidRangeRef = 5;
Error_InvalidGridRef = 6;
Error_InvalidNrOfParams = 7;
Error_CircularReference = 8;
Error_NoOpenParenthesis = 9;
Error_NoCloseParenthesis = 10;
Error_PrematureEndOfFormula = 11;
Error_UnknownError = 12;
Error_InvalidQualifier = 13;
Error_InvalidTokenAtPosition= 14;
Error_Overflow = 15;
Error_Underflow = 16;
Error_CircularRange = 17;
The string function handling is equivalent, as shown in this sample code:
function TStringMathLib.CalcStrFunction(FuncName: string; Params: TStringList; var ErrType, ErrParam: Integer): String; var i: Integer; s: string; begin Result := ''; ErrType := 0; if Params.Count = 0 then begin ErrType := Error_InvalidNrOfParams; Exit; end; Result := ''; if FuncName = 'REVERSE' then begin s := Params.Strings[0]; for i := 1 to Length(s) do Result := Result + s[Length(s)- i + 1]; end; if FuncName = 'CAPITALIZE' then begin s := Params.Strings[0]; for i := 1 to Length(s) do if (i = 1) or ( (i > 1) and (s[i - 1]=' ')) then Result := Result + upcase(s[i]) else Result := Result + s[i]; end; end; function TStringMathLib.HandlesStrFunction(FuncName: string): Boolean; begin Result := (FuncName = 'REVERSE') or (FuncName = 'CAPITALIZE'); end;
Function parameter hints
An additional feature of a function library is the capability to provide parameter hints while entering the function in TAdvSpreadGrid. This capability is enabled with the method : GetEditHint. This method is called during editing when entering parameters for a function that the library implements. The library should return a string that contains the hint text. This hint text can contain HTML formatting tags. The ParamIndex parameter of the method GetEditHint indicates the index of the parameter being entered. This can be used to highlight with a tag, the parameter being entered.Example
function TMyMathLib.GetEditHint(FuncName: string; ParamIndex: Integer): string; begin if FuncName = 'MYPROC' then begin case ParamIndex of 1: Result := 'MyProc(<b>n: Integer Value: string)<HR>Returns the n''character from string Value'; 2: Result := 'MyProc(n: Integer;<b> Value: string)<HR>Returns the n''character from string Value'; end; end; end;
In this example, the first parameter is bold, when the user is entering the first parameter and the 2nd parameter is bold when the user is entering the 2nd parameter.
×