CrossTab has a lot of overhead. Here is the version of UserDataSet:
Just release 1 stringgrid, 1 button, 1 frxReport, 1 frxUserDataSet in the form.
Set the frxUserDataSet, Form OnCreate, and Buttom OnClick events, as shown below.
No need to create reports or set any properties, all will be set or generated at runtime.
This seems to be faster than the cross-tab version, but you need to code more and lose CrossObject functionality.
Edit: Add comments and correct the erroneous calculation of PaperWidth.
Edit2: Add a print version that divides data into pages.
Show friendly version show in 1 single page as stringgrid:
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 ie 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.
The print version, which is a little more complicated and shares data on different pages for printing:
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 ie 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.