6

FastReportを使用していますが、1000行を超えるグリッドをプレビュー/印刷する必要があり、パフォーマンスに問題があります。エンドユーザーがグリッドの表示(使用される列、列の名前、サイズ)を変更する可能性があるため、通常はTfrxCrossObjectを使用してグリッドを準備します。そのため、動的に印刷する必要があります。単純なグリッド(16列x 2000行)をテストしましたが、最初のプレビューページを表示するのに10秒以上かかります。パフォーマンスを改善するためのアイデアはありますか?

編集: いくつかの回答で述べたように、問題は:あまり効率的ではないように見えるTFrxCrossObjectを使用せずにFastReportで「動的に」グリッド(画面上にあるのと同じ列名とサイズ)を作成する方法です。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.
4

2 に答える 2

4

CrossTab には多くのオーバーヘッドがあります。UserDataSet バージョンは次のとおりです。

  1. 1 つの stringgrid、1 つのボタン、1 つの frxReport、1 つの frxUserDataSet をフォームにドロップするだけです。

  2. 以下のコードのように、frxUserDataSet イベント、Form OnCreate および Buttom OnClick を設定します。

  3. レポートをデザインしたり、プロパティを設定したりする必要はありません。実行時にすべてが設定または生成されます。

クロスタブ バージョンよりも高速に見えますが、より多くのコーディングが必要であり、CrossObject の機能が失われています。

編集: いくつかのコメントを追加し、PaperWidth の計算ミスを修正します。

Edit2 : データをページに分割する印刷に適したバージョンを追加します。

stringgrid として 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.
于 2012-03-13T19:13:00.907 に答える
2

PrintStringGridコードの一部は、わずかに変更されたFastReportのデモに対応しています(16ではなくRowCount = 2000)。

大きなデータを処理する必要がある場合は、TStringGridをコンテナーとして使用することはお勧めできません。これは、プレゼンテーションの問題にのみ使用する必要があります。

メモリ内のデータセット(たとえば、質問コメントスレッドで提案されているteranとしてのClientDataset)を使用します。使用が必須である場合でも、TStringGridに大きなデータを提示できますが、TDBGridの方が適切です。

大きなTDatasetを繰り返すことは、単なるTStringGridで同じことを行うよりも高速です。

FastReportのPrintTableデモは出発点として役立つ可能性があり、PrintStringGridデモと同じコンポーネントを使用していることを知って、演習としてそれを適応させることができます。

  • TfrxReportと
  • 反復が行われるTfrxCrossObject。
于 2012-03-14T05:05:40.890 に答える