We help IT Professionals succeed at work.

How to print athe contents of a TStringGrid ?

syloux
syloux asked
on
How to print athe contents of a TStringGrid using QuickReport ? Thanks.
Comment
Watch Question

CERTIFIED EXPERT
Top Expert 2004

Commented:
there are some free components at www.torry.ru,
which are doing this without using quickreport

Commented:
Hi syloux,

I fount this Article in my Knowledge Base.


By simply using the Tprinter.Canvas.TextOut method, in most cases, the result is not so good; the text is not wrapped and the corresponding line is truncated .
Indeed, in order to print correctly such a String Grid, the right way is to use the DrawText API function.
So well, but this fuction requires the rectangular coordinates of each cell. Easy to do, is not it, by using the TstringGrid. CellRect method. Yes, of course, but in this case, only the visible cells on the screen are printed!
Not really fun.
Thus, the main idea of the algorithm is to construct for each cell of the String Grid, by the mean of the Rect function, the corresponding rectangle. In order to do that, the Left, Top, Right, Bottom points are needed.
We can note that the Left and the Right points are the same for all the rows, only the Top and Bottom points are variable, depending on the content of the cells in the rows.
Hence, starting from an origin TPoint, say Left:= 0 and Top:= 0, the Left end the Right points are constructed recursively, by using the TstringGrid. ColWidths property. Since the dimension of the String Grid (i.e. the number of the rows and the columns) should not be known, it would be a good practice to use a variant array in D3 or a dynamic array in D4 to store these points.
The Top and the Bottom points are also constructed recursively, row by row, by using the TstringGrid. RowHeights property.
06/23/99 - Just after the publication of this paper, somebody asked to me how to do to have the titles of each column on the top of each new page. In order to do that, we must insert the first row (Rows[0]) when we get a new page, during the scan process of the rows of the String Grid and we have to decrease the counter of the loop to begin the next line with the correct row.
So, the solution is to use a repeat loop instead of a for loop.
Here is the (revised) code.
procedure PrintGrid(var GenStrGrid : TStringGrid);
const
FinalBot = 1100; //poPortrait, 783 poLandScape;
var
OldCursor : TCursor;
PrnRect : TRect;
I, J, K, ATop, ABot, NC, NR, XScale, YScale, LBot : Integer;
GString : String;
LRMatrix : Variant;
begin
OldCursor := Screen.Cursor;
Screen.Cursor := crHourGlass;
NC := (GenStrGrid.ColCount - 1);
NR := (GenStrGrid.RowCount - 1);
LRMatrix := VarArrayCreate([0, NC, 0,1], VarInteger);
I := 0;
try
begin
repeat
if I = 0 then
begin
LRMatrix[I,0] := 0;
LRMatrix[I,1] := GenStrGrid.ColWidths[0];
Inc(I,1);
end
else
begin
LRMatrix[I,0] := LRMatrix[(I - 1),0] + GenStrGrid.ColWidths[(I - 1)] + 1;
LRMatrix[I,1] := LRMatrix[(I - 1),1] + GenStrGrid.ColWidths[I] + 1;
Inc(I,1);
end;
until
I > NC;
with Printer do
begin
XScale := GetDeviceCaps(Printer.Handle,LogPixelsX) div Self.PixelsPerInch;
YScale := GetDeviceCaps(Printer.Handle,LogPixelsY) div Self.PixelsPerInch;
Title := '';
Canvas.Font := Self.Font;
Orientation := poPortrait;
Begindoc;
J := 0;
repeat
if J = 0 then
begin
ATop := 0;
ABot := GenStrGrid.RowHeights[J];
LBot := ABot;
end
else
begin
ATop := ATop + GenStrGrid.RowHeights[(J - 1)] + 1;
ABot := ABot + GenStrGrid.RowHeights[J] + 1;
LBot := ABot;
end;
if LBot > FinalBot then
begin
ATop := 0;
ABot := GenStrGrid.RowHeights[0];
NewPage;
for K := 0 to NC do
begin
PrnRect := Rect(LRMatrix[K,0], ATop, LRMatrix[K,1], ABot);
with PrnRect do
begin
Left := Left * XScale;
Right := (Right - 3) * XScale;
Top := (20 + Top) * YScale;
Bottom := (20 + Bottom) * YScale;
end;
GString := GenStrGrid.Cells[K,0];
Canvas.Font.Style := [fsBold] + [fsUnderline];
DrawText(Canvas.Handle, PChar(GString), StrLen(PChar(GString)), PrnRect, DT_WORDBREAK);
end;
Dec(J,1);
ABot := GenStrGrid.RowHeights[J];
end
else
begin
for K := 0 to NC do
begin
PrnRect := Rect(LRMatrix[K,0], ATop, LRMatrix[K,1], ABot);
with PrnRect do
begin
Left := Left * XScale;
Right := (Right - 3) * XScale;
Top := (20 + Top) * YScale;
Bottom := (20 + Bottom) * YScale;
end;
GString := GenStrGrid.Cells[K,J];
if J = 0 then
Canvas.Font.Style := [fsBold] + [fsUnderline]
else
Canvas.Font.Style := [fsBold];
DrawText(Canvas.Handle, PChar(GString), StrLen(PChar(GString)), PrnRect, DT_WORDBREAK);
end;
end;
Inc(J,1);
until
J > NR;
EndDoc;
end;
end;
finally
begin
Screen.Cursor := OldCursor;
LRMatrix := UnAssigned;
end;
end;
end.


good luck

Cesario

Commented:
sorry syloux,

I was too fast. you whant to print the stringGrid with Quickreport.

Why ? If you add the Quickreport-VCL to your Project ( 730 KB)  only to print the stringGrid. I think its too much.

But if you whant to do it with Quickreport. so I can send you the complete source.

Best Regards

Cesario
Commented:

You can use the event OnNeedData :


...
  private
    ListData : TStringList ;
    Index    : Integer ;


procedure TQuickReport1.MyPrint(Var MyGrid : TStringGrid) ;
Var i : Integer ;
begin
  ListData := TStringList.Create ;

  For i := 1 To MyGrid.RowCount - 1 Do
    ListData.Add(MyGrid.Cells[0, i]) ;

  Print ;
end;

procedure TQuickReport1.QuickRepBeforePrint(Sender: TCustomQuickRep;
  var PrintReport: Boolean);
begin
  Index  := 0 ;
end;



procedure TQuickReport1.QuickRepNeedData(Sender: TObject;
  var MoreData: Boolean);
begin
  MoreData := (Index < ListData.Count) ;

  If MoreData Then
    QRLabel1.Caption := ListData.Strings[Index] ;
 
  Inc(Index) ;
end;