В руководстве разработчика FastReport стр. 40 - 41. приведен пример модуля для подключения библиотеки своих функций, который работает для FastReport 3.18 (FastScript 1.7). К сожалению, документация не обновляется и этот пример тоже."Чайнику" остается с трудом разбираться в сообщениях этого форума. Вот как мне в итоге удалось изменить этот модуль, чтобы все заработало с FastReport 3.20 (модуль достатачно добавить в проект).
unit myfunctions;
interface
uses SysUtils, Classes, fs_iinterpreter;
implementation
type
TFunctions = class(TfsRTTIModule)
private
function CallMethod(Instance: TObject; ClassType: TClass; const MethodName: String; var Params: Variant): Variant;
public
constructor Create(AScript: TfsScript); override;
end;
function MyFunc(str:string):string;
begin
// нужная логика
end;
constructor TFunctions.Create(AScript: TfsScript);
begin
inherited Create(AScript);
with AScript do
AddMethod('function MyFunc(str:string):string', CallMethod, 'Мои функции', 'Функция MyFunc');
end;
function TFunctions.CallMethod(Instance: TObject; ClassType: TClass;
const MethodName: String; var Params: Variant): Variant;
begin
if UpperCase(MethodName) = 'MYFUNC' then Result := MyFunc(Params[0]);
end;
1. Изменить наследника
type
TMyFunction = class(TfsRTTIModule)
2. Изменить заголовок
function CallMethod(Instance: TObject; ClassType: TClass; const MethodName:
String; Caller: TfsMethodHelper): Variant;
2.1 Регистрация функции:
constructor TMyFunction .Create(AScript: TfsScript);
begin
inherited Create(AScript);
with AScript do
begin
AddMethod(...);
end;
end.
3. Доступ к параметрам функции
Caller.Params[0], Caller.Params[1] и т.д
4. И если надо
initialization
fsRTTIModules.Add(TMyFunction);
Здравствуйте, прочитал ваш ответ по поводу подключения своих функций в fastreport и подправил свой код, который работал в FR3.19, по вашему совету под FR 3.21, но результат отрицательный.
Помогите пожалуйста разобрать где я не досмотрел. Проект горит.
Пример кода:
unit frRoubleUnit;
interface
uses Classes, fs_iinterpreter, SysUtils, math;
type
TFunctions = class(TfsRTTIModule) //class(TObject)
private
function CallMethod(Instance: TObject; ClassType: TClass;
const MethodName: String; Caller: TfsMethodHelper): Variant;
public
constructor Create(AScript: TfsScript);
destructor Destroy; override;
end;
Function RealToRouble(c:Double; Currency: integer):String;
Function NumToStr(s:String):String;
var
Functions: TFunctions;
Script: TfsScript;
implementation
Function NumToStr(s:String):String;{Возвращает число прописью}
Begin
//Логика
End;{NumToStr}
Function RealToRouble(c:Double; Currency: integer):String;
begin {Возвращает число прописью с рублями и копейками}
//Логика
end;
constructor TFunctions.Create(AScript: TfsScript);
begin
inherited Create(AScript);
with AScript do // здесь возникает Exception Access Vialation
begin
AddedBy := Self;
AddMethod('Function NumToStr(s:String):String', CallMethod,
'ctOther',
'Функция NumToStr возвращает число прописью.');
AddMethod('Function RealToRouble(c:Double; Currency: integer):String', CallMethod,
'ctOther',
'Функция RealToRouble возвращает денежную сумму прописью.');
AddedBy := nil;
end;
end;
destructor TFunctions.Destroy;
begin
if fsGlobalUnit <> nil then fsGlobalUnit.RemoveItems(Self);
inherited;
end;
function TFunctions.CallMethod(Instance: TObject; ClassType: TClass;
const MethodName: String; Caller: TfsMethodHelper): Variant;
begin
if MethodName = 'NUMTOSTR' then Result := NumToStr(Caller.Params[0])
else if MethodName = 'REALTOROUBLE' then Result := RealToRouble(Caller.Params[0],Caller.Params[1]);
end;
1) Деструктор классу TFunctions не нужен.
2) finalization Functions.Free; - тоже не нужно.
3) Переменные Functions: TFunctions; Script: TfsScript; -не нужны.
4) в initialization должно быть только fsRTTIModules.Add(TFunctions); создавать объект не нужно.
Смотрите вышеприведенный вариант, в него кроме своей логики добавлять ничего не нужно.
1) Деструктор классу TFunctions не нужен.
2) finalization Functions.Free; - тоже не нужно.
3) Переменные Functions: TFunctions; Script: TfsScript; -не нужны.
4) в initialization должно быть только fsRTTIModules.Add(TFunctions); создавать объект не нужно.
Смотрите вышеприведенный вариант, в него кроме своей логики добавлять ничего не нужно.
Спасибо, все получилось. Еще одно замечание возникло по поводу форматирования полей Memo. Ситуация такая же то, что раньше работало в 3.18 в 3.21 выдает ошибку. Например, MemoNN.Memo =
[qCurrency."Prefix"][qForAllDocJournalItem."TotalSum"][qCurrency."Postfix"]
формат поля число %2.2f
взависимости от валюты, например рубль выводилось 1000р.
если доллар - $1000
а теперь в версии 3.21 возникает ошибка: Could not convert variant of type (String) into type (Double).
Выполняя по шагом я заметил что отдельно форматируется значения полей БД а не целиком Memo-поле [qForAllDocJournalItem."TotalSum"] т.е. 1000, отдельно [qCurrency."Postfix"] т.е. р. но уже с ошибкой.
Получается, что frReport встретив в Memo-поле поле БД [qForAllDocJournalItem."TotalSum"] со значением 1000 форматирует его в 1000.00 а потом встретив [qCurrency."Postfix"] со значение р. пытается и его отформатировать в число %2.2f и естественно возникает ошибка.
Как избегали такую ситуацию в версии 3.18 и на что можно обратить внимание чтоб это исправить?
Спасибо.
[qCurrency."Prefix"] и [qCurrency."Postfix"] - наверное поля типа string, а формат мемо float.
FR пытается перевести содержимое мемо в Double, но так как мемо содержить текст появляется ошибка.
Поставьте формат мемо в текст, а для вывода поля [qForAllDocJournalItem."TotalSum"] в нужном формате используйте функцию FormatFloat.
[qCurrency."Prefix"] и [qCurrency."Postfix"] - наверное поля типа string, а формат мемо float.
FR пытается перевести содержимое мемо в Double, но так как мемо содержить текст появляется ошибка.
Поставьте формат мемо в текст, а для вывода поля [qForAllDocJournalItem."TotalSum"] в нужном формате используйте функцию FormatFloat.
Вы все верно поняли и написали но глупость ситуации в том что это в таком виде работало в предыдущих версиях FR
Комментарии
unit myfunctions;
interface
uses SysUtils, Classes, fs_iinterpreter;
implementation
type
TFunctions = class(TfsRTTIModule)
private
function CallMethod(Instance: TObject; ClassType: TClass; const MethodName: String; var Params: Variant): Variant;
public
constructor Create(AScript: TfsScript); override;
end;
function MyFunc(str:string):string;
begin
// нужная логика
end;
constructor TFunctions.Create(AScript: TfsScript);
begin
inherited Create(AScript);
with AScript do
AddMethod('function MyFunc(str:string):string', CallMethod, 'Мои функции', 'Функция MyFunc');
end;
function TFunctions.CallMethod(Instance: TObject; ClassType: TClass;
const MethodName: String; var Params: Variant): Variant;
begin
if UpperCase(MethodName) = 'MYFUNC' then Result := MyFunc(Params[0]);
end;
initialization
fsRTTIModules.Add(TFunctions);
end.
Помогите пожалуйста разобрать где я не досмотрел. Проект горит.
Пример кода:
unit frRoubleUnit;
interface
uses Classes, fs_iinterpreter, SysUtils, math;
type
TFunctions = class(TfsRTTIModule) //class(TObject)
private
function CallMethod(Instance: TObject; ClassType: TClass;
const MethodName: String; Caller: TfsMethodHelper): Variant;
public
constructor Create(AScript: TfsScript);
destructor Destroy; override;
end;
Function RealToRouble(c:Double; Currency: integer):String;
Function NumToStr(s:String):String;
var
Functions: TFunctions;
Script: TfsScript;
implementation
Function NumToStr(s:String):String;{Возвращает число прописью}
Begin
//Логика
End;{NumToStr}
Function RealToRouble(c:Double; Currency: integer):String;
begin {Возвращает число прописью с рублями и копейками}
//Логика
end;
constructor TFunctions.Create(AScript: TfsScript);
begin
inherited Create(AScript);
with AScript do // здесь возникает Exception Access Vialation
begin
AddedBy := Self;
AddMethod('Function NumToStr(s:String):String', CallMethod,
'ctOther',
'Функция NumToStr возвращает число прописью.');
AddMethod('Function RealToRouble(c:Double; Currency: integer):String', CallMethod,
'ctOther',
'Функция RealToRouble возвращает денежную сумму прописью.');
AddedBy := nil;
end;
end;
destructor TFunctions.Destroy;
begin
if fsGlobalUnit <> nil then fsGlobalUnit.RemoveItems(Self);
inherited;
end;
function TFunctions.CallMethod(Instance: TObject; ClassType: TClass;
const MethodName: String; Caller: TfsMethodHelper): Variant;
begin
if MethodName = 'NUMTOSTR' then Result := NumToStr(Caller.Params[0])
else if MethodName = 'REALTOROUBLE' then Result := RealToRouble(Caller.Params[0],Caller.Params[1]);
end;
initialization
Functions := TFunctions.Create(Script);
fsRTTIModules.Add(TFunctions);
finalization
Functions.Free;
end.
2) finalization Functions.Free; - тоже не нужно.
3) Переменные Functions: TFunctions; Script: TfsScript; -не нужны.
4) в initialization должно быть только fsRTTIModules.Add(TFunctions); создавать объект не нужно.
Смотрите вышеприведенный вариант, в него кроме своей логики добавлять ничего не нужно.
Спасибо, все получилось. Еще одно замечание возникло по поводу форматирования полей Memo. Ситуация такая же то, что раньше работало в 3.18 в 3.21 выдает ошибку. Например, MemoNN.Memo =
[qCurrency."Prefix"][qForAllDocJournalItem."TotalSum"][qCurrency."Postfix"]
формат поля число %2.2f
взависимости от валюты, например рубль выводилось 1000р.
если доллар - $1000
а теперь в версии 3.21 возникает ошибка: Could not convert variant of type (String) into type (Double).
Выполняя по шагом я заметил что отдельно форматируется значения полей БД а не целиком Memo-поле [qForAllDocJournalItem."TotalSum"] т.е. 1000, отдельно [qCurrency."Postfix"] т.е. р. но уже с ошибкой.
Получается, что frReport встретив в Memo-поле поле БД [qForAllDocJournalItem."TotalSum"] со значением 1000 форматирует его в 1000.00 а потом встретив [qCurrency."Postfix"] со значение р. пытается и его отформатировать в число %2.2f и естественно возникает ошибка.
Как избегали такую ситуацию в версии 3.18 и на что можно обратить внимание чтоб это исправить?
Спасибо.
FR пытается перевести содержимое мемо в Double, но так как мемо содержить текст появляется ошибка.
Поставьте формат мемо в текст, а для вывода поля [qForAllDocJournalItem."TotalSum"] в нужном формате используйте функцию FormatFloat.