Recent

Author Topic: [SOLVED] Adding columns to a Word document table (FPVectorial)  (Read 1238 times)

JD

  • Hero Member
  • *****
  • Posts: 1758
Hi there everyone,

I am using the FPVectorial library to create a Word/ODF document that contains a table with 2 columns. According to the example on this page http://wiki.lazarus.freepascal.org/fpvectorial_-_Text_Document_Support#Simple_Table in the Wiki, a table is created with ONE column by default and to add another column, it is necessary to use AddColWidths.

However, AddColWidths is no longer available!! It looks like the code has been refactored and AddColWidths has been removed.

My code is as shown below:

Code: Pascal  [Select]
  1.     AttitudesTable                 := Page.AddTable;
  2.     AttitudesTable.PreferredWidth   := Dimension(100, dimPercent);
  3.     AttitudesTable.ColWidthsUnits   := dimMillimeter;
  4.     AttitudesTable.AddColWidths(50);      <------ This does not work any more!!!
  5.  

How can I create a second column in my Attitudes table?

Thanks a lot for your kind assistance.

Cheers,

JD
« Last Edit: April 17, 2019, 04:20:52 pm by JD »
Windows (10, 7) - Lazarus 2.0RC3/FPC 3.2, NewPascal, Delphi

Indy 10.6 series; mORMot; Zeos 7.2.1; SQLite, Firebird, PostgreSQL & MariaDB; VirtualTreeView 5.5.3 R1

JD

  • Hero Member
  • *****
  • Posts: 1758
Re: Adding columns to a Word document table (FPVectorial)
« Reply #1 on: April 16, 2019, 01:43:39 pm »
Any ideas? Anyone?  :D :D
Windows (10, 7) - Lazarus 2.0RC3/FPC 3.2, NewPascal, Delphi

Indy 10.6 series; mORMot; Zeos 7.2.1; SQLite, Firebird, PostgreSQL & MariaDB; VirtualTreeView 5.5.3 R1

JD

  • Hero Member
  • *****
  • Posts: 1758
Re: Adding columns to a Word document table (FPVectorial)
« Reply #2 on: April 16, 2019, 02:57:52 pm »
Alternatively, can one add 2 cells horizontally side by side in the same row?

JD
« Last Edit: April 16, 2019, 04:20:28 pm by JD »
Windows (10, 7) - Lazarus 2.0RC3/FPC 3.2, NewPascal, Delphi

Indy 10.6 series; mORMot; Zeos 7.2.1; SQLite, Firebird, PostgreSQL & MariaDB; VirtualTreeView 5.5.3 R1

Mike.Cornflake

  • Hero Member
  • *****
  • Posts: 1249
Re: Adding columns to a Word document table (FPVectorial)
« Reply #3 on: April 16, 2019, 06:29:40 pm »
I'm away from code right now, but what happens when you run the example code?

Also - I note you have typed AddColWidths.  The call is (or should be) AddColWidth (ie singluar)
Code: Pascal  [Select]
  1. Table.AddColWidth(50);

UPDATE:
Ug.  Looking at the pas file online (https://svn.freepascal.org/svn/lazarus/trunk/components/fpvectorial/fpvectorial.pas), I concur that call is no longer present.  No idea who removed it or why :-(   It'll be more than a few days before I get a chance to look at this though.

UPDATE2:
It's been more than 4 years since I wrote that code.  Looking through docxvectorialwriter.pas.Procedure ProcessTable(ATable: TvTable);  ColWidths is optional.  It's sufficient to add Cells to a row to determine column count.
Reading the comments on the wiki - looks like ColWidths is ONLY essential if you're merging cells AND writing to ODT.

All I can suggest is you try, and in a few days I'll try and understand if a change has been made and why.
« Last Edit: April 16, 2019, 07:09:26 pm by Mike.Cornflake »
Lazarus Trunk/FPC Trunk on Windows [7, 10]
  Have you tried searching this forum or the wiki?:   http://wiki.lazarus.freepascal.org/Alternative_Main_Page
  BOOKS! (Free and otherwise): http://wiki.lazarus.freepascal.org/Pascal_and_Lazarus_Books_and_Magazines

JD

  • Hero Member
  • *****
  • Posts: 1758
Re: Adding columns to a Word document table (FPVectorial)
« Reply #4 on: April 16, 2019, 07:46:45 pm »
@Mike.Cornflake

Thank you very much for your reply. I was getting desperate.  :D

I looked at the code for TvTable. It is defined as follows:

Code: Pascal  [Select]
  1.   (*
  2.       Note on the grid used for the table
  3.  
  4.       For the table shown below, three ColWidths must be defined.
  5.  
  6.       First row should only have 2 cells. First cell spans 2 columns.
  7.       Second row should only have 2 cells. Second cell spans 2 columns.
  8.       Third row should have 3 cells.  Each cell only spans 1 column (default)
  9.  
  10.    X,Y +-----+------+---------+
  11.        |            |         |
  12.        +-----+----------------+
  13.        |     |                |
  14.        +-----+------+---------+
  15.        |     |      |         |
  16.        +-----+------+---------+
  17.  
  18.        The table draws at X,Y and downwards
  19.   *)
  20.  
  21.   // TvTable.Style should be a Table Style, not a Paragraph Style
  22.   // and is optional.
  23.   TvTable = class(TvEntityWithStyle)
  24.   private
  25.     Rows: TFPList;
  26.     ColWidthsInMM: array of Double;   // calculated during Render
  27.     TableWidth, TableHeight: Double;  // in mm; calculated during Render
  28.     procedure CalculateColWidths(constref ARenderInfo: TvRenderInfo);
  29.     procedure CalculateRowHeights(constref ARenderInfo: TvRenderInfo);
  30.   public
  31.     ColWidths: array of Double;       // Can be left empty for simple tables
  32.                                       // MUST be fully defined for merging cells
  33.     ColWidthsUnits : TvUnits;         // Cannot mix ColWidth Units.
  34.     Borders : TvTableBorders;         // Defaults: single/black/inside and out
  35.     PreferredWidth : TvDimension;     // Optional. Units mm.
  36.     SpacingBetweenCells: Double;      // Units mm. Gap between Cells.
  37.     CellSpacingLeft, CellSpacingRight, CellSpacingTop,
  38.       CellSpacingBottom: Double;      // space around each side of cells, in mm
  39.     BackgroundColor : TFPColor;       // Optional.
  40.  
  41.     constructor create(APage : TvPage); override;
  42.     destructor destroy; override;
  43.  
  44.     function AddRow: TvTableRow;
  45.     function GetRowCount : Integer;
  46.     function GetRow(AIndex: Integer) : TvTableRow;
  47.     //
  48.     function GetColCount(): Integer;
  49.     //
  50.     procedure Render(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean = True); override;
  51.     function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
  52.   end;
  53.  

There does not seem to be any way to add several columns to a table.
By the way, I must congratulate the authors of fpvectorial because it produces perfect Microsoft Word documents.
I was pleasantly surprised. I just need to be able to create multi-columned tables in those Word documents.

Cheers,

JD
« Last Edit: April 16, 2019, 07:49:36 pm by JD »
Windows (10, 7) - Lazarus 2.0RC3/FPC 3.2, NewPascal, Delphi

Indy 10.6 series; mORMot; Zeos 7.2.1; SQLite, Firebird, PostgreSQL & MariaDB; VirtualTreeView 5.5.3 R1

Mike.Cornflake

  • Hero Member
  • *****
  • Posts: 1249
Re: Adding columns to a Word document table (FPVectorial)
« Reply #5 on: April 16, 2019, 08:44:52 pm »
> There does not seem to be any way to add several columns to a table.

Add multiple cells to a row.   Go on, try it :-)   As I said before, looking at docxwriter, this should be sufficient.
Lazarus Trunk/FPC Trunk on Windows [7, 10]
  Have you tried searching this forum or the wiki?:   http://wiki.lazarus.freepascal.org/Alternative_Main_Page
  BOOKS! (Free and otherwise): http://wiki.lazarus.freepascal.org/Pascal_and_Lazarus_Books_and_Magazines

JD

  • Hero Member
  • *****
  • Posts: 1758
Re: Adding columns to a Word document table (FPVectorial)
« Reply #6 on: April 17, 2019, 11:30:57 am »
> There does not seem to be any way to add several columns to a table.

Add multiple cells to a row.   Go on, try it :-)   As I said before, looking at docxwriter, this should be sufficient.

I tried it but the resulting Word document is corrupted and cannot be opened. I added a second Cell := Row.AddCell; a line Cell2 := Row.AddCell; a fluent programming style with Cell := Row.AddCell.Row.AddCell; It all created unreadable Word documents

This is what I'm trying to do. I am trying to create a work schedule document with 2 columns: Days & Hours Worked.

The code I'm using is as follows (of course in the real world, the hours will be input manually):

Code: Pascal  [Select]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   Document: TvVectorialDocument;
  4.   Page: TvTextPageSequence;
  5.   BoldTextStyle: TvStyle;
  6.   HeaderParagraph, Paragraph: TvParagraph;
  7.   DaysTable: TvTable;
  8.   Row: TvTableRow;
  9.   Cell, Cell2: TvTableCell;
  10.   intRow, intTotalRows: integer;
  11.   DaysArray, HoursWorkedArray: array of string;
  12. begin
  13.   //
  14.   DaysArray := ['DAYS', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
  15.   HoursWorkedArray := ['HOURS WORKED', '4', '7', '8', '8', '4', '8', '0'];
  16.  
  17.   // Create the document
  18.   Document := TvVectorialDocument.Create;
  19.  
  20.   //
  21.   try
  22.      //  Adds the defaut Paragraph Styles
  23.     //    StyleTextBody, StyleHeading1,
  24.     //    StyleHeading2 & StyleHeading3
  25.     Document.AddStandardTextDocumentStyles(vfUnknown);
  26.  
  27.     // Add our own Style
  28.     BoldTextStyle             := Document.AddStyle();
  29.     BoldTextStyle.Kind        := vskTextSpan;
  30.     BoldTextStyle.Name        := 'Bold';
  31.     BoldTextStyle.Font.Bold   := True;
  32.     BoldTextStyle.SetElements := BoldTextStyle.SetElements + [spbfFontBold];
  33.  
  34.     // Add a page and a paragraph
  35.     Page                      := Document.AddTextPageSequence;
  36.     //
  37.     HeaderParagraph           := Page.AddParagraph;
  38.     HeaderParagraph.Style     := Document.StyleHeading1Centralized;
  39.     HeaderParagraph.AddText('WORK SCHEDULE');
  40.     HeaderParagraph           := Page.AddParagraph;
  41.  
  42.     // Add the Days table
  43.     DaysTable                  := Page.AddTable;
  44.     DaysTable.PreferredWidth   := Dimension(100, dimPercent);
  45.     DaysTable.ColWidthsUnits   := dimMillimeter;
  46.  
  47.     // Get the number of rows to add to the table
  48.     intTotalRows := Length(DaysArray);
  49.     //
  50.     for intRow := 0 to Pred(intTotalRows) do
  51.     begin
  52.       Row                            := DaysTable.AddRow;
  53.       if intRow = 0 then
  54.       begin
  55.         Row.BackgroundColor := RGBToFPColor(192, 192, 192); // Grey Shading
  56.         Row.Header := True; // Tell the table this is a Header Row
  57.       end;
  58.       Cell                           := Row.AddCell;
  59.       Paragraph                      := Cell.AddParagraph;
  60.       Paragraph.Style                := Document.StyleTextBody;
  61.       Paragraph.AddText(DaysArray[intRow]).Style := BoldTextStyle;
  62.     end;
  63.  
  64.     try
  65.       // Save the document
  66.       Document.WriteToFile('Work schedule.docx', vfDOCX);
  67.     except
  68.       raise;
  69.     end;
  70.   finally
  71.     Document.Free;
  72.   end;
  73. end;
  74.  

The resulting Microsoft Word document created from the code above is in the attachment. This is where I am as of today. Any help will be greatly appreciated.

Thanks,

JD
Windows (10, 7) - Lazarus 2.0RC3/FPC 3.2, NewPascal, Delphi

Indy 10.6 series; mORMot; Zeos 7.2.1; SQLite, Firebird, PostgreSQL & MariaDB; VirtualTreeView 5.5.3 R1

Mike.Cornflake

  • Hero Member
  • *****
  • Posts: 1249
Re: Adding columns to a Word document table (FPVectorial)
« Reply #7 on: April 17, 2019, 12:01:14 pm »
Yup - as you say - it's broken.  I've confirmed the full write test I wrote no longer works.

Here's the original function

Code: Pascal  [Select]
  1. function TvTable.AddColWidth(AValue: Double): Integer;
  2. begin
  3.   SetLength(ColWidths, Length(ColWidths) + 1);
  4.   ColWidths[High(ColWidths)] := AValue;
  5. end;

ColWidths is an array of double, and it's in TvTable.Public.   So you can implement your own AddColWidth and see if that produces a working docx :-(

Sorry about this :-(

Mike

UPDATE:

In order to get fpvtextwritetest2 to run, I added the following helper routine.

Code: Pascal  [Select]
  1.     Procedure AddColWidth(ATable: TvTable; AValue: Double);
  2.     begin
  3.       SetLength(ATable.ColWidths, Length(ATable.ColWidths) + 1);
  4.       ATable.ColWidths[High(ATable.ColWidths)] := AValue;
  5.     end;    

I then changed all calls from
Code: Pascal  [Select]
  1.     CurTable.AddColWidth( 15);
  2.     CurTable.AddColWidth(20);
  3.     CurTable.AddColWidth(20);
  4.     CurTable.AddColWidth(20);
  5.     CurTable.AddColWidth(79.5); // For Word (and possibly odt), this only has to be close.

to

Code: Pascal  [Select]
  1.     AddColWidth(CurTable, 15);
  2.     AddColWidth(CurTable, 20);
  3.     AddColWidth(CurTable, 20);
  4.     AddColWidth(CurTable, 20);
  5.     AddColWidth(CurTable, 79.5); // For Word (and possibly odt), this only has to be close.

Result Word Document was well formed and worked.

When I'm back on land I'll submit a patch and get the original code restored.   Either that or get the author of revision 55389 to update the wiki.  My preference is original code restored.


« Last Edit: April 17, 2019, 12:26:31 pm by Mike.Cornflake »
Lazarus Trunk/FPC Trunk on Windows [7, 10]
  Have you tried searching this forum or the wiki?:   http://wiki.lazarus.freepascal.org/Alternative_Main_Page
  BOOKS! (Free and otherwise): http://wiki.lazarus.freepascal.org/Pascal_and_Lazarus_Books_and_Magazines

JD

  • Hero Member
  • *****
  • Posts: 1758
Re: Adding columns to a Word document table (FPVectorial)
« Reply #8 on: April 17, 2019, 12:38:00 pm »
@Mike.Cornflake

No need to be sorry.

I added a class helper to my code as follows:

Code: Pascal  [Select]
  1. type
  2.   { TvTableHelper }
  3.   TvTableHelper = class helper for TvTable
  4.   public
  5.     function AddColWidth(AValue: Double): Integer;
  6.   end;
  7.  
  8. { TvTableHelper }
  9.  
  10. function TvTableHelper.AddColWidth(AValue: Double): Integer;
  11. begin
  12.   SetLength(ColWidths, Length(ColWidths) + 1);
  13.   ColWidths[High(ColWidths)] := AValue;
  14. end;
  15.  
  16.  

My new document creation code now becomes:

Code: Pascal  [Select]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   Document: TvVectorialDocument;
  4.   Page: TvTextPageSequence;
  5.   BoldTextStyle: TvStyle;
  6.   HeaderParagraph, Paragraph: TvParagraph;
  7.   DaysTable: TvTable;
  8.   Row: TvTableRow;
  9.   Cell, Cell2: TvTableCell;
  10.   intRow, intTotalRows: integer;
  11.   DaysArray, HoursWorkedArray: array of string;
  12. begin
  13.   //
  14.   DaysArray := ['DAYS', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
  15.   HoursWorkedArray := ['HOURS WORKED', '4', '7', '8', '8', '4', '8', '0'];
  16.  
  17.   // Create the document
  18.   Document := TvVectorialDocument.Create;
  19.  
  20.   //
  21.   try
  22.      //  Adds the defaut Paragraph Styles
  23.     //    StyleTextBody, StyleHeading1,
  24.     //    StyleHeading2 & StyleHeading3
  25.     Document.AddStandardTextDocumentStyles(vfUnknown);
  26.  
  27.     // Add our own Style
  28.     BoldTextStyle             := Document.AddStyle();
  29.     BoldTextStyle.Kind        := vskTextSpan;
  30.     BoldTextStyle.Name        := 'Bold';
  31.     BoldTextStyle.Font.Bold   := True;
  32.     BoldTextStyle.SetElements := BoldTextStyle.SetElements + [spbfFontBold];
  33.  
  34.     // Add a page and a paragraph
  35.     Page                      := Document.AddTextPageSequence;
  36.     //
  37.     HeaderParagraph           := Page.AddParagraph;
  38.     HeaderParagraph.Style     := Document.StyleHeading1Centralized;
  39.     HeaderParagraph.AddText('WORK SCHEDULE');
  40.     HeaderParagraph           := Page.AddParagraph;
  41.  
  42.     // Add the Days table
  43.     DaysTable                  := Page.AddTable;
  44.     DaysTable.PreferredWidth   := Dimension(100, dimPercent);
  45.     DaysTable.ColWidthsUnits   := dimMillimeter;
  46.     // Add 2 columns
  47.     DaysTable.AddColWidth(50);
  48.     DaysTable.AddColWidth(50);
  49.  
  50.     // Get the number of rows to add to the table
  51.     intTotalRows := Length(DaysArray);
  52.     //
  53.     for intRow := 0 to Pred(intTotalRows) do
  54.     begin
  55.       Row                            := DaysTable.AddRow;
  56.       if intRow = 0 then
  57.       begin
  58.         Row.BackgroundColor := RGBToFPColor(192, 192, 192); // Grey Shading
  59.         Row.Header := True; // Tell the table this is a Header Row
  60.       end;
  61.       Cell                           := Row.AddCell;
  62.       Paragraph                      := Cell.AddParagraph;
  63.       Paragraph.Style                := Document.StyleTextBody;
  64.       Paragraph.AddText(DaysArray[intRow]).Style := BoldTextStyle;
  65.     end;
  66.  
  67.     try
  68.       // Save the document
  69.       Document.WriteToFile('Work schedule.docx', vfDOCX);
  70.     except
  71.       raise;
  72.     end;
  73.   finally
  74.     Document.Free;
  75.   end;
  76. end;
  77.  

But it stll creates a table with one column!! What is it that I am missing?

Thanks a lot for your assistance,

JD
Windows (10, 7) - Lazarus 2.0RC3/FPC 3.2, NewPascal, Delphi

Indy 10.6 series; mORMot; Zeos 7.2.1; SQLite, Firebird, PostgreSQL & MariaDB; VirtualTreeView 5.5.3 R1

JD

  • Hero Member
  • *****
  • Posts: 1758
Re: Adding columns to a Word document table (FPVectorial)
« Reply #9 on: April 17, 2019, 12:39:51 pm »
I didn't see the updates you added to your last post. I'll try them now.....
Windows (10, 7) - Lazarus 2.0RC3/FPC 3.2, NewPascal, Delphi

Indy 10.6 series; mORMot; Zeos 7.2.1; SQLite, Firebird, PostgreSQL & MariaDB; VirtualTreeView 5.5.3 R1

JD

  • Hero Member
  • *****
  • Posts: 1758
Re: Adding columns to a Word document table (FPVectorial)
« Reply #10 on: April 17, 2019, 12:56:03 pm »
It worked!!!! Thanks a lot Mike.Cornflake.

I'll post the final solution later today to help those who might be facing a similar problem.

JD
Windows (10, 7) - Lazarus 2.0RC3/FPC 3.2, NewPascal, Delphi

Indy 10.6 series; mORMot; Zeos 7.2.1; SQLite, Firebird, PostgreSQL & MariaDB; VirtualTreeView 5.5.3 R1

Mike.Cornflake

  • Hero Member
  • *****
  • Posts: 1249
Re: Adding columns to a Word document table (FPVectorial)
« Reply #11 on: April 17, 2019, 12:59:59 pm »
I've never used Class Helpers.  Can't see why your code didn't work, but glad we finally got there :-)   

Many thanks for your patience with this issue.
Lazarus Trunk/FPC Trunk on Windows [7, 10]
  Have you tried searching this forum or the wiki?:   http://wiki.lazarus.freepascal.org/Alternative_Main_Page
  BOOKS! (Free and otherwise): http://wiki.lazarus.freepascal.org/Pascal_and_Lazarus_Books_and_Magazines

JD

  • Hero Member
  • *****
  • Posts: 1758
Re: Adding columns to a Word document table (FPVectorial)
« Reply #12 on: April 17, 2019, 01:03:28 pm »
I've never used Class Helpers.  Can't see why your code didn't work, but glad we finally got there :-)   

Many thanks for your patience with this issue.

The code with the class helper and your own code all work perfectly now.  :D

Class helpers extend the functionality of existing classes without the need of modifying the classes themselves. I use them when I am not the author of a class and I either don't have the source code for the class OR I don't want to modify it so that I don't break anything.

JD
Windows (10, 7) - Lazarus 2.0RC3/FPC 3.2, NewPascal, Delphi

Indy 10.6 series; mORMot; Zeos 7.2.1; SQLite, Firebird, PostgreSQL & MariaDB; VirtualTreeView 5.5.3 R1

JD

  • Hero Member
  • *****
  • Posts: 1758
Re: Adding columns to a Word document table (FPVectorial)
« Reply #13 on: April 17, 2019, 04:20:20 pm »
Here is the sample published project in case anyone has a similar problem.

JD
« Last Edit: April 17, 2019, 04:37:43 pm by JD »
Windows (10, 7) - Lazarus 2.0RC3/FPC 3.2, NewPascal, Delphi

Indy 10.6 series; mORMot; Zeos 7.2.1; SQLite, Firebird, PostgreSQL & MariaDB; VirtualTreeView 5.5.3 R1

qindj

  • Newbie
  • Posts: 2
Re: Adding columns to a Word document table (FPVectorial)
« Reply #14 on: October 24, 2019, 03:10:23 pm »
Here is the sample published project in case anyone has a similar problem.

JD

Hi, JD

thanks for your example, it's very helpful.

I have another question, do you know why we should add a space after a single char , otherwise it will become empty?

As i tested, every single char such as 'A', 'B', or '1', '2'... will be empty in saved docx or odt file