unit cross32; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Qrctrls, quickrpt, DB, DBTables, ExtCtrls; type Tfrmxtab = class(TForm) QuickRep1: TQuickRep; Query1: TQuery; QRSubDetail1: TQRSubDetail; QRDBText1: TQRDBText; QRDBText2: TQRDBText; QRGroup1: TQRGroup; QRLabel1: TQRLabel; QRLabel2: TQRLabel; QRSubDetail2: TQRSubDetail; QRLabel3: TQRLabel; Query1Customers: TIntegerField; Query1State: TStringField; QRBand1: TQRBand; TitleBand1: TQRBand; QRMemo1: TQRMemo; QRLabel4: TQRLabel; QRLabel5: TQRLabel; QRLabel6: TQRLabel; procedure QRSubDetail2BeforePrint(Sender: TQRCustomBand; var PrintBand: Boolean); procedure QuickRep1BeforePrint(Sender: TQuickRep; var PrintReport: Boolean); procedure QRBand1BeforePrint(Sender: TQRCustomBand; var PrintBand: Boolean); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } public { Public declarations } { Define a matix array for 50 states with 2 columns } Matrix: array [1..50,1..2] of string; qrlStates, qrlCustomers: array [0..10] of TQRLabel; Row: integer; { Global variable to track the current row in the matrix} end; var frmxtab: Tfrmxtab; implementation {$R *.DFM} procedure Tfrmxtab.QRSubDetail2BeforePrint(Sender: TQRCustomBand; var PrintBand: Boolean); begin { We don't print this band out, but we need this event to populate our array with the contents of the dataset. This is not the only method for doing this. You could populate the array before you run the report and use BeforePrint event of the band to just output the data. } PrintBand := False; { For the purposes of this example, we are limiting the report to only the first 10 states returned in the dataset } if Row < 10 then begin Inc(Row); { Now we fill our array, each state gets it's own row. We are basicly building a copy of the dataset in memory, because it's faster to navigate the array when dong a crosstab report. } Matrix[row,1] := IntToStr(Query1Customers.Value); Matrix[row,2] := Query1State.Value; end; end; procedure Tfrmxtab.QuickRep1BeforePrint(Sender: TQuickRep; var PrintReport: Boolean); begin Row := 0; end; procedure Tfrmxtab.QRBand1BeforePrint(Sender: TQRCustomBand; var PrintBand: Boolean); var nIdx: integer; begin { Now we "rotate" the data to ouput the crosstab report } qrlStates[0].Caption := 'States:'; qrlCustomers[0].Caption := 'Customers:'; for nIdx := 1 to 10 do begin qrlStates[nIdx].Caption := Matrix[nIdx,2]; qrlCustomers[nIdx].Caption := Matrix[nIdx,1]; if qrlStates[nIdx].Caption = '' then qrlStates[nIdx].Caption := 'N/A'; end; end; procedure Tfrmxtab.FormCreate(Sender: TObject); var MyWidth, nIdx: integer; begin MyWidth := Trunc(QRBand1.Width / 11); for nIdx := 0 to 10 do begin qrlStates[nIdx] := TQRLabel.Create(frmxtab); qrlCustomers[nIdx] := TQRLabel.Create(frmxtab); with qrlStates[nIdx] do begin Parent := QRBand1; AlignToBand := False; AutoSize := False; AutoStretch := False; Color := clWhite; Top := 64; if nIdx = 0 then begin Left := 0; Width := MyWidth+6; end else begin Left := MyWidth * nIdx + 6; Width := MyWidth - 6; end; Font.Style := [fsItalic,fsBold]; qrlCustomers[nIdx].Parent := qrlStates[nIdx].Parent; qrlCustomers[nIdx].AligntoBand := qrlStates[nIdx].AligntoBand; qrlCustomers[nIdx].AutoSize := qrlStates[nIdx].AutoSize; qrlCustomers[nIdx].AutoStretch := qrlStates[nIdx].AutoStretch; qrlCustomers[nIdx].Color := qrlStates[nIdx].Color; qrlCustomers[nIdx].Top := qrlStates[nIdx].Top + qrlStates[nIdx].Height + 10; qrlCustomers[nIdx].Left := qrlStates[nIdx].Left; qrlCustomers[nIdx].Width := qrlStates[nIdx].Width; end end; end; procedure Tfrmxtab.FormDestroy(Sender: TObject); var nIdx: integer; begin for nIdx := 0 to 10 do begin qrlStates[nIdx].Free; qrlCustomers[nIdx].Free; end; end; end.