delphi - FastReport TFrxCrossObject 和大型网格(> 1000 行)的性能

标签 delphi grid fastreport

我使用 FastReport,需要预览/打印超过 1000 行的网格,并且遇到一些性能问题。 通常,我使用 TfrxCrossObject 来准备网格,因为最终用户可能会更改网格演示(使用的列、列的名称、大小),因此我需要动态打印。 我测试了一个简单的网格(16 列 x2000 行),它需要 10 秒以上才能呈现第一个预览页面。 有什么提高性能的想法吗?

编辑: 正如一些答案中所述,问题是:如何在 FastReport 中“动态”创建网格(具有与屏幕上相同的列名称和大小),而不使用 TFrxCrossObject,这似乎不是很有效。我可能承认所有解决方案,例如使用 DataSet 或增强 TfrxCrossObject。

测试代码:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  frxClass, StdCtrls, Grids, frxCross;

type
  TForm1 = class(TForm)
    Button1: TButton;
    StringGrid1: TStringGrid;
    frxCrossObject1: TfrxCrossObject;
    frxReport1: TfrxReport;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure frxReport1BeforePrint(c: TfrxReportComponent);
  end;

var
  Form1: TForm1;

implementation
{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
var
  i, j: Integer;
begin
  for i := 1 to 16 do
    for j := 1 to 2000 do
      StringGrid1.Cells[i - 1, j - 1] := IntToStr(i * j);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  frxReport1.ShowReport;
end;

procedure TForm1.frxReport1BeforePrint(c: TfrxReportComponent);
var
  Cross: TfrxCrossView;
  i, j: Integer;
begin
  if c is TfrxCrossView then
  begin
    Cross := TfrxCrossView(c);
    for i := 1 to 16 do
      for j := 1 to 2000 do
        Cross.AddValue([i], [j], [StringGrid1.Cells[i - 1, j - 1]]);
  end;
end;
end.

最佳答案

交叉表有很多开销。这是 UserDataSet 版本:

  1. 只需在表单中放入 1 个 stringgrid、1 个按钮、1 个 frxReport、1 个 frxUserDataSet。

  2. 设置frxUserDataSet事件、Form OnCreate和Buttom OnClick,如下代码。

  3. 无需设计报表或设置任何属性,所有内容都将在运行时设置或生成。

它似乎比交叉表版本更快,但您需要更多编码并且丢失了 CrossObject 的功能。

编辑:添加一些注释并修复 PaperWidth 错误计算。

Edit2:添加一个适合打印的版本,将数据拆分为页面。

查看友好版本显示在 1 个单页中作为字符串网格:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, frxClass, Grids, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    StringGrid1: TStringGrid;
    frxReport1: TfrxReport;
    frxUserDataSet1: TfrxUserDataSet;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure frxUserDataSet1Next(Sender: TObject);
    procedure frxUserDataSet1GetValue(const VarName: string; var Value: Variant);
    procedure frxUserDataSet1CheckEOF(Sender: TObject; var Eof: Boolean);
    procedure frxUserDataSet1First(Sender: TObject);
  private
    X, Y, TCol, TRow : Integer;
    IsEof : Boolean;
    CW, CH, PF : Double;
    Page : TfrxReportPage;
    MDB : TfrxMasterData;
    Memo : TfrxMemoView;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
var
  BW : Double;
begin
  IsEof := False;
  Page.PaperWidth :=  CW * TCol + 20; // EndlessWidth seems not work with band column
  MDB.SetBounds(0,0, CW * PF * TCol, CH * PF);
  MDB.Columns := TCol;
  MDB.ColumnWidth := CW * PF;
  frxReport1.ShowReport;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i, j : Integer;
begin
  CW := 12; // Cell Width in mm
  CH := 5;  // Cell Height in mm
  PF := 3.7794; // Pixie Factor i.e. the conversion of mm to FR component measurement
  TCol := 2000; // Total Column
  TRow := 16; // Total Row

  for i := 1 to TRow do
    for j := 1 to TCol do
      StringGrid1.Cells[i - 1, j - 1] := IntToStr(i * j);

  frxUserDataSet1.Fields.Text := 'Data';
  frxReport1.Clear;
  frxReport1.DataSets.Add(frxUserDataSet1);
  Page := TfrxReportPage.Create(frxReport1);
  Page.CreateUniqueName;
  Page.TopMargin := 10;
  Page.BottomMargin := 10;
  Page.LeftMargin := 10;
  Page.RightMargin := 10;
  Page.EndlessHeight := True;
  Page.EndlessWidth := True;
  MDB := TfrxMasterData.Create(Page);
  MDB.DataSet := frxUserDataSet1;
  Memo := TfrxMemoView.Create(MDB);
  Memo.SetBounds(0,0,CW * PF,CH * PF);
  Memo.Memo.Text := '[frxUserDataSet1."Data"]';
  Memo.Frame.Typ := [ftLeft, ftRight, ftTop, ftBottom];
end;

procedure TForm1.frxUserDataSet1CheckEOF(Sender: TObject; var Eof: Boolean);
begin
  Eof := IsEof;
end;

procedure TForm1.frxUserDataSet1First(Sender: TObject);
begin
  X := 0;
  Y := 0;
end;

procedure TForm1.frxUserDataSet1GetValue(const VarName: string; var Value: Variant);
begin
  Value := StringGrid1.Cells[X,Y];
end;

procedure TForm1.frxUserDataSet1Next(Sender: TObject);
begin
  If Y = TCol - 1 then
  begin
    if X = TRow - 1 then
      IsEof := True;
    Inc(X);
    Y := 0;
  end
  else
    Inc(Y);
end;

end.

打印友好的版本有点复杂,并且在不同页面中单独打印数据:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, frxClass, Grids, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    StringGrid1: TStringGrid;
    frxReport1: TfrxReport;
    frxUserDataSet1: TfrxUserDataSet;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure frxUserDataSet1Next(Sender: TObject);
    procedure frxUserDataSet1GetValue(const VarName: string; var Value: Variant);
    procedure frxUserDataSet1CheckEOF(Sender: TObject; var Eof: Boolean);
    procedure frxUserDataSet1First(Sender: TObject);
  private
    X, Y, TCol, TRow, RPP, ColBreak : Integer;
    IsEof : Boolean;
    CW, CH, PF : Double;
    Page : TfrxReportPage;
    MDB : TfrxMasterData;
    Memo : TfrxMemoView;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses Math;

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
var
  BW : Double;
begin
  IsEof := False;
  RPP := Ceil((Page.PaperHeight - Page.TopMargin - Page.BottomMargin) / CH) - 1; // Row per page
  ColBreak := RPP; // break to next column

  frxReport1.ShowReport;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i, j : Integer;
begin
  CW := 12; // Cell Width in mm
  CH := 5;  // Cell Height in mm
  PF := 3.7794; // Pixil Factor i.e. the conversion of mm to FR component measurement
  TCol := 2000; // Total Column
  TRow := 16; // Total Row

  for i := 1 to TRow do
    for j := 1 to TCol do
      StringGrid1.Cells[i - 1, j - 1] := IntToStr(i * j);

  frxUserDataSet1.Fields.Text := 'Data';
  frxReport1.Clear;
  frxReport1.DataSets.Add(frxUserDataSet1);
  Page := TfrxReportPage.Create(frxReport1);
  Page.CreateUniqueName;
  Page.TopMargin := 10;
  Page.BottomMargin := 10;
  Page.LeftMargin := 10;
  Page.RightMargin := 10;
  Page.Columns := Ceil(Page.PaperWidth / CW);
  MDB := TfrxMasterData.Create(Page);
  MDB.DataSet := frxUserDataSet1;
  MDB.SetBounds(0,0, CW * PF, CH * PF);
  Memo := TfrxMemoView.Create(MDB);
  Memo.Align := baClient;
  Memo.Memo.Text := '[frxUserDataSet1."Data"]';
  Memo.Frame.Typ := [ftLeft, ftRight, ftTop, ftBottom];
end;

procedure TForm1.frxUserDataSet1CheckEOF(Sender: TObject; var Eof: Boolean);
begin
  Eof := IsEof;
end;

procedure TForm1.frxUserDataSet1First(Sender: TObject);
begin
  X := 0;
  Y := 0;
end;

procedure TForm1.frxUserDataSet1GetValue(const VarName: string; var Value: Variant);
begin
  Value := StringGrid1.Cells[X,Y];
end;

procedure TForm1.frxUserDataSet1Next(Sender: TObject);
begin
  If X = TRow - 1 then
  begin
    if Y = TCol - 1 then
      IsEof := True
    else
    begin
      frxReport1.Engine.NewColumn;
      Inc(Y);
      X := ColBreak - RPP;
    end;
  end
  else if (X = ColBreak - 1) then
  begin
    if Y = TCol - 1 then
    begin
      frxReport1.Engine.NewPage;
      ColBreak := ColBreak + RPP;
      Y := 0;
    end
    else
      Inc(Y);
    frxReport1.Engine.NewColumn;
    X := ColBreak - RPP;
  end
  else
    Inc(X);
end;

end.

关于delphi - FastReport TFrxCrossObject 和大型网格(> 1000 行)的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9649875/

相关文章:

delphi - 什么是内部错误E5912

delphi - 如何使两个控件各自占据其父级区域的一半?

使用 SDL 的 C++ 为 CAD 类型的应用程序制作网格

extjs - 在 ExtJS 中使用重新配置创建有状态网格

model-view-controller - Telerik MVC grid-如何设置默认行选择

delphi - 如果类型 (Array Variant) 无法将变体转换为类型 (OleStr)

delphi - 如果调用 FastReport.PrepareReport,则 ISAPI Web 应用程序挂起

Delphi:EmbeddedWB 奇怪的代理错误?

mysql - 如何在 Delphi 7 中连接 FastReport 和 MySQL 5.5?

delphi - Delphi XE4 RAD Studio 中的 DFM 布局问题