Recent

Author Topic: [SOLVED] How Do I Print a StringGrid with all its Contents?  (Read 4594 times)

PasCoder

  • New Member
  • *
  • Posts: 34
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #15 on: October 17, 2022, 10:02:01 am »
Dear J-G
Thank you for your help. I've fixed the page orientation issue. But the two challanges mentioned are not yet fixed. I still need more help.

Thank you

wp

  • Hero Member
  • *****
  • Posts: 11910
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #16 on: October 17, 2022, 05:20:27 pm »
A new version in the attachment, v4.

Now I redid everything as a component, TGridPrinter, which gives a lot more flexibility in adding features:
  • Event handler OnPrepareCanvas to prepare individual cell formatting (different background color, different font, workbreak, different alignment, ...)
  • Individual colors for outer border, separator line between fixed and normal cells, cell grid lines.
  • Header and footer, each one consisting of a left-aligned, centered, and right-aligned part, plus additional separating line
  • Symbols $PAGE, $PAGECOUNT, $DATE, $TIME can be inserted in any header/footer string to display the current page number, page count, printing date and time, e.g. GridPrinter.Header[hfpCenter] := 'Page $PAGE of $PAGECOUNT'.
  • Page breaks in both directions, i.e. when the grid is too wide and when the grid is too high. PrintOrder defines whether the rows are scanned first or the columns are scanned first for a pagebreak.
  • Property for page orientation
  • When the grid option goCellEllipsis is set, the ellipsis '...' is also added to the print-out if the text is longer than the cell width.
To use the component, you must first create it (of course), then assign the grid to be printed to the Grid property, and then call the Print method. BUT: The grid is very elemental, and the type defined does not know the Cells property of the TStringGrid. Therefore you MUST provide a handler for the OnGetCellText event in which the text to be displayed in a given cell is passed over to the printer. This may sound complicated but the big advantage is that the GridPrinter can be used by all descendants of TCustomGrid.

Code: Pascal  [Select][+][-]
  1. uses
  2.   GridPrn;
  3. ...
  4. var
  5.   FGridPrinter: TGridPrinter;
  6. begin
  7.   FGridPrinter := TGridPrinter.Create(self);
  8.   FGridPrinter.Grid := StringGrid1;
  9.   FGridPrinter.OnGetCellText := @PrinterGetCellText;
  10. ...
  11.   FGridPrinter.Print;
  12. ...
  13.   FGridPrinter.Free;
  14. end;
  15.  
  16. procedure TForm1.PrinterGetCellText(Sender: TObject; AGrid: TCustomGrid;
  17.   ACol, ARow: Integer; var AText: String);
  18. begin
  19.   if AGrid is TStringGrid then
  20.     AText := TStringGrid(AGrid).Cells[ACol, ARow];
  21. end;

I am attaching the unit gridprn as well as my test project.

PasCoder

  • New Member
  • *
  • Posts: 34
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #17 on: October 18, 2022, 12:27:41 am »
Dear WP, This is superb!!!! Thank you very much.

I've compiled your example and it works well. Now I'm trying to integrate into my Project.
However, I have a little challange with the OnPrepareCanvas . I have a column with a PickList as its editor. This PickList has names of different colors such that when a user picks up a color, that entire row is painted with that color. But it seems I'm failing to adapt it to the code you've provided. Please, look at my code and guide me;

Code: Pascal  [Select][+][-]
  1. if (Sender as TStringGrid).Cells[4, aRow] = 'AntiqueWhite' then begin
  2.   (Sender as TStringGrid).Canvas.Brush.Color := TColor($FAEBD7);
  3.   end else if (Sender as TStringGrid).Cells[4, aRow] = 'Aqua' then begin
  4.   (Sender as TStringGrid).Canvas.Brush.Color := TColor($00FFFF);
  5.   end else if (Sender as TStringGrid).Cells[4, aRow] = 'Aquamarine' then begin
  6.   (Sender as TStringGrid).Canvas.Brush.Color := TColor($7FFFD4);
  7.   end else if (Sender as TStringGrid).Cells[4, aRow] = 'Azure' then begin
  8.   (Sender as TStringGrid).Canvas.Brush.Color := TColor($F0FFFF);
  9.   end else if (Sender as TStringGrid).Cells[4, aRow] = 'Beige' then begin
  10.   (Sender as TStringGrid).Canvas.Brush.Color := TColor($F5F5DC);
  11.   end

The compilation is fine but when it comes to printing, it throws an error on those color names (strings) in the fourth column cells. I've also attached an image to show this runtime error.

Thanks

wp

  • Hero Member
  • *****
  • Posts: 11910
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #18 on: October 18, 2022, 01:17:24 am »
I did not test it, but I guess the problem is that the Sender of the TGridPrinter's OnPrepareCanvas is the GridPrinter, rather than the StringGrid. Therefore the cast of Sender to TStringGrid must fail.

Since you are reading cell content here you should call the function GetCellText of the GridPrinter. However, this function is in the protected section of the class and thus not accessible from the outside. You should move the line "function GetCellText(ACol, ARow: Integer): String; virtual;" from the protected to the public section.

Code: Pascal  [Select][+][-]
  1. type
  2.   TGridPrinter = class(TComponent)
  3.   private
  4.     ...
  5.   protected
  6.     // function GetCellText(ACol, ARow: Integer): String; virtual;  // <--- remove here
  7.     ...
  8.   public
  9.     constructor Create(AOwner: TComponent); override;
  10.     destructor Destroy; override;
  11.     function GetCellText(ACol, ARow: Integer): String; virtual;   // <--- and insert here
  12.     ...
  13.   end;
   
And then you can modify the OnPrepareCanvas as follows so that is can be used by both TStringGrid and TGridPrinter:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.StringGrid1PrepareCanvas(Sender: TObject; aCol, aRow: Integer;
  2.   aState: TGridDrawState);
  3. var
  4.   lCanvas: TCanvas;
  5. begin
  6.   // Use the correct canvas
  7.   if Sender is TStringGrid then
  8.     lCanvas := TStringGrid(Sender).Canvas
  9.   else if Sender is TGridPrinter then
  10.     lCanvas := Printer.Canvas
  11.   else
  12.     exit;
  13.  
  14.   // Get the text from the cell at col=4 and row=ARow
  15.   if Sender is TStringGrid then
  16.     s := TStringGrid(Sender).Cells[4, ARow]
  17.   else if Sender is TGridPrinter then
  18.     s := TGridPrinter(Sender).GetCellText(4, ARow);
  19.  
  20.   // Set the canvas brush color as defined by the cell text
  21.   if s = 'AntiqueWhite' then
  22.     lCanvas.Brush.Color := TColor($FAEBD7)
  23.   else if s = 'Aqua' then
  24.     lCanvas.Brush.Color := TColor($00FFFF)
  25.   else if s = 'Aquamarine' then
  26.     lCanvas.Brush.Color := TColor($7FFFD4)
  27.   else if s = 'Azure' then
  28.     lCanvas.Brush.Color := TColor($F0FFFF)
  29.   else if s = 'Beige' then
  30.     lCanvas.Brush.Color := TColor($F5F5DC);
  31. end;
« Last Edit: October 18, 2022, 01:21:26 am by wp »

PasCoder

  • New Member
  • *
  • Posts: 34
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #19 on: October 18, 2022, 10:13:29 am »
Dear wp, I can't thank you enough for your support. I'm learning a lot from your code.
I've fixed the OnPrepareCanvas as per your advice and the Project compiles well without any error.
However, when I print, the page is almost empty! It only shows the Column Headers only!
I've attached the Image to show the output. What else should I do?

Thanks

wp

  • Hero Member
  • *****
  • Posts: 11910
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #20 on: October 18, 2022, 11:03:16 am »
Is there a handler for OnGetCellText?

Besides that, I wonder why the border lines are not drawn correctly? Can you show me the code related to printing?

PasCoder

  • New Member
  • *
  • Posts: 34
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #21 on: October 18, 2022, 01:12:13 pm »
Apart from the one that you provided below, I've not provided any other. So, I used the one in your Project


Code: Pascal  [Select][+][-]
  1. procedure TFormAKJV.PrinterGetCellText(Sender: TObject; AGrid: TCustomGrid;
  2.   ACol, ARow: Integer; var AText: String);
  3. begin
  4.   if AGrid is TStringGrid then
  5.     AText := TStringGrid(AGrid).Cells[ACol, ARow];
  6. end;

Below is the Print Button Event

Code: Pascal  [Select][+][-]
  1. procedure TFormAKJV.Button1Click(Sender: TObject);
  2. begin
  3.   if PrintDialog1.Execute then
  4.     FGridPrinter.Print;
  5. end;

Also, in the PrepareCanvas I have this code for wordWrap. Does it also have a problew?

Code: Pascal  [Select][+][-]
  1. var
  2.     lCanvas: TCanvas;
  3.     s: String;
  4.     ts: TTextStyle;
  5.   begin
  6.     ts := ChapterStringGrid.Canvas.TextStyle;
  7.     ts.SingleLine := False;
  8.     ts.Wordbreak := True;
  9.     ChapterStringGrid.Canvas.TextStyle := ts;

Thanks

wp

  • Hero Member
  • *****
  • Posts: 11910
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #22 on: October 18, 2022, 01:17:05 pm »
What is type of grid that you are connecting to the TGridPrinter? In an earlier note I got the impression that it might be a TKGrid which should not work at all here.

The attached v5 works for TStringGrids "out of the box", i.e. a handler for OnGetCellText is not needed any more. (It is still needed for TDBGrid). The test project was extended to contain a cell with a color name which is interpreted in the OnPrepareCanvas event as background color of this cell (in a bit simpler way than what I explained earlier).

wp

  • Hero Member
  • *****
  • Posts: 11910
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #23 on: October 19, 2022, 12:23:37 am »
v6 creates a print preview as a bitmap which can be displayed easily in a TImage embedded in a TScrollbox and enhanced by a toolbar with print and page navigation buttons as well as zoom factor combobox and zooming by mouse-wheel.

I moved development to my github repository now: https://github.com/wp-xyz/LazSamples/tree/master/grids/gridprinter.
« Last Edit: October 19, 2022, 12:41:19 am by wp »

bonmario

  • Sr. Member
  • ****
  • Posts: 346
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #24 on: October 19, 2022, 11:32:59 am »
v6 creates a print preview as a bitmap which can be displayed easily in a TImage embedded in a TScrollbox and enhanced by a toolbar with print and page navigation buttons as well as zoom factor combobox and zooming by mouse-wheel.

I moved development to my github repository now: https://github.com/wp-xyz/LazSamples/tree/master/grids/gridprinter.

Hi you did a great job !!!
I think I have found a problem: if Grid has "FixedCols = 0", both preview and print are wrong!

Maybe there is also a problem when the columns have the width equal to 0 (I use this trick to hide some "service" columns), but this I am still checking

Thanks, Mario

wp

  • Hero Member
  • *****
  • Posts: 11910
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #25 on: October 19, 2022, 12:32:35 pm »
I think I have found a problem: if Grid has "FixedCols = 0", both preview and print are wrong!

Maybe there is also a problem when the columns have the width equal to 0 (I use this trick to hide some "service" columns), but this I am still checking
"FixedCol = 0" issue fixed in last commit.

I don't see a problem with ColWidth = 0.

bonmario

  • Sr. Member
  • ****
  • Posts: 346
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #26 on: October 19, 2022, 01:14:53 pm »
Thank you !!!
You're right, there's no problem, I was wrong.

P.S. Am I or I can't find it, or is there no property that allows you to change the margins?

Thanks again, Mario

wp

  • Hero Member
  • *****
  • Posts: 11910
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #27 on: October 19, 2022, 01:26:50 pm »
You're right - forgotten to publish. Done now.

bonmario

  • Sr. Member
  • ****
  • Posts: 346
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #28 on: October 19, 2022, 02:32:03 pm »
Perfect, thank you again !!!

PasCoder

  • New Member
  • *
  • Posts: 34
Re: [SOLVED] How Do I Print a StringGrid with all its Contents?
« Reply #29 on: October 21, 2022, 07:40:32 pm »
You're right - forgotten to publish. Done now.

Dear wp,
I want to say thank you for such a superb support especially to me. I've pulled the final version from GitHub and it has worked fine.

Can you support me a little more with row auto Height adjustment to fit the cell content when wordwrap is enabled. I've also attached an image.

Thanks

 

TinyPortal © 2005-2018