Пользовательские функции - как получить доступ к отчету?

отредактировано January 2009 Раздел: FastReport 4.0
В старом FR (2.xx) работал код CurReport.FindObject. Как получить из пользовательской функции доступ к отчету (в частности, для вызова FindObject etc)? Спасибо. Кстати, пример кода было бы неплохо включить в справку (вместо/вместе с формулировкой "// нужная логика ")

Комментарии

  • gpigpi
    отредактировано 20:27
    Передавайте имя отчёта в скриптовую переменную
    procedure TForm1.frxReport1BeginDoc(Sender: TObject);
    begin
         if Sender is TfrxReport then
         TfrxReport(Sender).Script.Variables['ReportName']:=TfrxReport(Sender).Name;
    end;
    
    затем передавайте значение переменной в качестве параметра пользовательской функции
  • отредактировано January 2009
    Может, не совсем точно объяснил? Тогда извиняюсь.
    Есть реализация функции
      TFunctions = class(TfsRTTIModule)
      private
        function CallMethod(Instance: TObject; ClassType: TClass;
          const MethodName: String; var Params: Variant): Variant;
      public
        constructor Create(AScript: TfsScript); override;
      end;
    
    constructor TFunctions.Create(AScript: TfsScript);
    begin
      inherited Create(AScript);
      with AScript do begin
        AddMethod('function rmSetUserHeaderById(HeaderId: Integer): string',
                  CallMethod, PERSPECTIVE,
                  'Устанавливает текст пользовательского заголовка, читая его из справочника заголовков');
      end;
    end;
    
    function TFunctions.CallMethod(Instance: TObject; ClassType: TClass;
      const MethodName: string; var Params: Variant): Variant;
    begin
      if UpperCase(MethodName) = 'RMSETUSERHEADERBYID' then begin
        // как вот тут получить доступ к отчету и его объектам?
            // хочется написать что-то вроде Report.FindObject(VarToStr(Params[1]) as Tfrx...
      end;
    end;
    
    Если ее трассировать - то при вызове Instance == nil; ClassType == nil
    Все это происходит при вызовах через com, внутри модуля, где реализуется собственно функция, нет формы (точнее, я не уверен, что там есть в момент вызова). Я думал, что ссылка на отчет есть внутри AScript (и в конструкторе можно до нее добраться), или внутри TfsRTTIModule - но навскидку найти ничего пока не удалось...
    Раньше (в FR 2) работал такой вот код:
    procedure TFrTBFunctionLibrary.DoFunction(FNo: Integer; p1, p2, p3: Variant;
      var val: Variant);
    begin
      CurReport.FindObject(frParser.Calc(p3)) as TfrRichView
    end;
    
    Свойство CurReport, видимо, было внутри TfrFunctionLibrary (исходники не читал, честно говоря).
  • gpigpi
    отредактировано January 2009
    Непонятно, зачем Вам это нужно. Вызывайте Вашу при выводе требуемого объекта отчёта - и всё. Т.е. в требуемом TfrxRichView наберите
    [rmSetUserHeaderById(HeaderId)]
    А что вы подразумеваете под пользовательским заголовком?
  • отредактировано January 2009
    Что такое "пользовательский заголовок" - это не важно (rtf, формируемый где-то в другом месте и для построения отчета читаемый из базы).
    Задача примерно такая: при построении отчета в TfrxRichView надо поместить rtf, который читается из базы данных (чтение там непростое, потому непосредстенно отчет доступа к ней не имеет). Раньше (в FR 2) функции передавалось имя TfrxRichView (напр., Rich1), далее внутри этой функции работал код, который находит rtf и помещает его внутрь этого Rich1:
        
      Rich := CurReport.FindObject(frParser.Calc(p3)) as TfrRichView;
      Rich.RichEdit.Clear;
      Rich.RichEdit.PlainText := False;
      Rich.RichEdit.Text := v.RtfText;
      // тут v - объект, который возвращает rtf
    
    В FR4 мне не удается внутри функции
    function TFunctions.CallMethod(Instance: TObject; ClassType: TClass;
      const MethodName: string; var Params: Variant): Variant;
    
    получить доступ к этому самому объекту типа TfrxRichView (я не знаю, как это сделать). Если же возвращать rtf-строку как результат функции
        
    function TFunctions.CallMethod(Instance: TObject; ClassType: TClass;
      const MethodName: string; var Params: Variant): Variant;
    begin  
      Result := v.RtfText;
    end;
    
    то не получается отобразить этот rtf.
    Я сделал тестовый пример (больше - для проверки). Получается, что вот такой код работает
    var
      s: TStringStream;
    begin
      s := TStringStream.Create(MyRtfString);
      // здесь MyRtfString - та самая строка, содержащая нужный rtf
      try
        with TfrxRichView(frxReport1.FindObject('Rich1')) do begin
          RichEdit.PlainText := False;
          RichEdit.Lines.LoadFromStream(s);
        end;
      finally
        s.Free();
      end;
    
    а вот такой код - не работает
      with TfrxRichView(frxReport1.FindObject('Rich1')) do begin
        RichEdit.PlainText := False;
        RichEdit.Lines.Text := MyRtfString;
      end;
    
    Т.е. чтобы отобразить rtf из строки, надо создать TStringStream, просто присвоить ее в Lines.Text нельзя. Но я же не могу внутри скрипта FastReport создать TStringStream? Вот и получается, что мне надо внутри моей функции получить доступ к объекту отчета.
    P.S. Я понимаю, что крайний случай - создать rtf-файл, в который поместить строку, вернуть в качестве значения функции его имя, и внутри скрипта отчета уже загрузить из этого файла rtf. Но по некоторым соображениям мне не хотелось бы использовать такой путь. Скажем так, если есть другая возможность нормальная возможность - предпочитаю обойтись без промежуточного файла.
    Спасибо за ответы!

    P.P.S.
    Еще интересный момент. Из Delphi работает вот такой код:
          
      Rich := frxReport.FindObject('Rich') as TfrxRichView;
      Rich.RichEdit.Clear();
      Rich.RichEdit.PlainText := False;
      Rich.RichEdit.Text := SomeRtfText;
    
    и Rtf показывается нормально. А при попытке написать в скрипте отчета
    Rich.RichEdit.Text := SomeRtfText;
    
    получается access violation.
  • gpigpi
    отредактировано 20:27
    Вот пример с использованием пользовательской функции:
    procedure TForm1.FormCreate(Sender: TObject);
    begin
         frxReport1.AddFunction('function LoadRTF(ReportName, RTFName: String)');
         frxReport1.ShowReport();
    end;
    
    procedure TForm1.frxReport1BeginDoc(Sender: TObject);
    begin
         if Sender is TfrxReport then
         TfrxReport(Sender).Script.Variables['ReportName']:=TfrxReport(Sender).Name;
    end;
    
    function TForm1.frxReport1UserFunction(const MethodName: String;
      var Params: Variant): Variant;
    begin
         if MethodName='LOADRTF' then
           TfrxRichView(TfrxReport(FindComponent(Params[0])).FindObject(Params[1])).RichEdit.Text:=
           '{\rtf1\ansi\ansicpg1251\deff0\deflang1049{\fonttbl{\f0\fswiss\fcharset0 Arial;}{\f1\fnil MS Sans Serif;}}'+
           '\viewkind4\uc1\pard\lang1033\f0\fs16 test\par'+
           '\b test\lang1049\b0\f1\par'+
           '}'; 
    end;
    
    в скрипте отчёта
    procedure Rich1OnBeforePrint(Sender: TfrxComponent);
    begin
         LoadRTF(<ReportName>, 'Rich1');
    end;
    
    написал:
    А при попытке написать в скрипте отчета
    Rich.RichEdit.Text := SomeRtfText;
    Попробуйте
    Rich1.RichEdit.Lines.Text:=
    '{\rtf1\ansi\ansicpg1251\deff0\deflang1049{\fonttbl{\f0\fswiss\fcharset0 Arial;}{\f1\fnil MS Sans Serif;}}'+
    '\viewkind4\uc1\pard\lang1033\f0\fs16 test\par'+
    '\b test\lang1049\b0\f1\par'+
    '}';

Оставить комментарий

Многофункциональный текстовый редактор. Чтобы отредактировать стиль параграфа, нажмите TAB, чтобы перейти к меню абзаца. Там вы можете выбрать стиль. По умолчанию не выбран ни один стиль. Когда вы выберете текст, появится встроенное меню форматирования. Нажмите TAB, чтобы войти в него. Некоторые элементы, такие как многофункциональные вставки ссылок, картинок, индикаторов загрузки и сообщений об ошибок могут быть вставлены в редактор. Вы можете перемещаться по ним, используя стрелки внутри редактора и удалять с помощью клавиш delete или backspace.