Create Table in Code - TableAdd

<< Click to Display Table of Contents >>

Navigation:  Programming > Create text under program control > Create Tables >

Create Table in Code - TableAdd

Very often you will have to create a table, for example a calculation.

 

This can be done best using the TableAdd procedure. This procedure requires only a few parameters, such as row cont and column count but can also work with a callback procedure which is executed for each created cell.

 

function TWPCustomRtfEdit.TableAdd(

  ColCount, RowCount: Integer;

  Options: TWPTableAddOptions = [];

  StyleForNewCells: TWPTextStyle = nil;

  CallBackForText: TWPTableAddCellEvent = nil;

  StyleForHeader: TWPTextStyle = nil;

  StyleForFooter: TWPTextStyle = nil;

  WidthSourceRow : TParagraph = nil;

  RowGroupLevel : Integer = 0

   ): TParagraph;

 

!

Especially for the use with callback procedures a new variant of TableAdd has been added to WPTools 9.

 

It accepts an anonymous procedure which makes it very easy to work with local variables and allows very compact code.

 

function TWPCustomRtfEdit.TableAdd(ColCount, RowCount: Integer;

    CallBackProcedure : TWPTableAddCellCallback;

    Options: TWPTableAddOptions=[]): TParagraph;

 

Example:

var num : Integer;

begin

  num := 1;

  WPRichText1.TableAdd(10,10,procedure(RowNr, ColNr: Integer; par: TParagraph)

     begin

        par.SetText(IntToStr(num));

        inc(num);

     end,[wptblActivateBorders]);

  WPRichText1.ReformatAll(false, true);

end;

 

Since the callback procedure receives information about the current column and row number it is easy to apply special properties to certain cells or preset the contents of the created cell.

 

Note: You can also use the Rows[r].Cols[c] arrays as described in the second part of this chapter but then you have to take care that you work with the correct row index. Using this arrays is probably also a little slower.

 

Please see reference for supported WPAT_ codes.

 

TableAdd also expects an option parameter which can have this flags:

 

wptblActivateBorders  - create a table with borders

wptblCreateHeaderRow - create a header row which is repeated on each page. RowNr will be -1 in callback

wptblCreateFooterRow - create a header row which is repeated on each page. RowNr will be -2 in callback

wptblAllowNestedTables - create a table in a cell

wptblPlaceCursorInLastCell - place the cursor in the last cell for subsequent text adding

wptblAppendTableAtEnd - the result of TableAdd will be the new table  and not the first cell

wptblDontApplyWritingAttr - do not use the current writing attributes

wptblRowsUseSameWidthPC - All rows use the same width as used in previous row

wptblContinueRowSpan - Continue rowspan cells found in previous row

wptblReuseCurrentParIfEmpty - Create the table instead of the current paragraph

   

// internally used: create a dynamic grid which is connected to a dataset.

// The ID must be set in the returned TParagraph objec.Name!

// (The Result of TableAdd() will be the new table  and not the first cell)

wptblCreateDynamicGrid

 

wptblPutCursorAfterTable -After the creation the cursor will be put in the next paragraph (which can be created)

wptblCreateCollapsibleRows- Add WPAT_PAR_GROUPLEVEL to all rows which are not header or footer

 

Create a table object which is not stored in the document but an independent object

wptblCreateTableAsFreeParagraph - the table TParagraph will be returned.

 

wptblCreateIndentColumn - Create a first indent cell in all rows, also header and footer!

wptblActivateBordersInIndentCol -  wptblActivateBorders also applies to indent column

wptblCreateSubHeader - Create a second table header row

wptblCreateSubHeader2 - Create a third table header row

wptblCreateSummaryFooter - Create a second footer row

wptblCreateSummaryFooter2 - Create a third footer row

wptblReturnCreatedTableObject - the table TParagraph will be returned.

 

1) Use TableAdd() with a callback function

 

1.1) This code will create a table with 5 rows:

 

procedure TForm1.AddCell(RowNr, ColNr: Integer; par: TParagraph);

begin

         par.SetText(Format('%d %d',[RowNr, ColNr]));

        if RowNr=1 then

            par.ASetColor(WPAT_FGColor, clGreen) else

        begin

            if (RowNr-1) and 1=1 then

                  par.ASetColor(WPAT_FGColor,clRed) // uneven

            else  par.ASetColor(WPAT_FGColor,clBlue); // even

        end;

end;

 

procedure TForm1.Button1Click(Sender: TObject);

begin

   WPRichText1.TableAdd(3,5,[wptblActivateBorders],nil, AddCell);

   WPRichText1.ReformatAll();

end;

 

1.2) It is also possible to create the following columns in a new row

 

In the callback add the flag wpstLevelEnd to par.State:

 

procedure TForm1.AddCell(RowNr, ColNr: Integer; par: TParagraph);

begin

 par.SetText(Format('r%d c%d',[RowNr, ColNr]));

if ColNr=2 then par.State := par.State + [wpstLevelEnd];

if ColNr>2 then par.ASetColor(WPAT_FGColor, clYellow);

end;

 

procedure TForm1.Button1Click(Sender: TObject);

begin

WPRichText1.TableAdd(5,3,

    [wptblActivateBorders,wptblReturnCreatedTableObject],

     nil, AddCell)

      .ASet(WPAT_BoxWidth, 3000);

WPRichText1.ReformatAll();

end;

 

clip0017

 

1.3) This code will append a new table to the end of the text:

 

 WPRichText1.TableAdd(7,7,

    [wptblActivateBorders,wptblAppendTableAtEnd],nil, InvoiceDemoCell);

 

 

This is a screen shot of the created table:

clip0102

 

The callback procedure InvoiceDemoCell is implemented like this

 

procedure TWPTableCalc.InvoiceDemoCell(RowNr, ColNr: Integer; par: TParagraph);

const prods : array[1..5] of string =

( 'Cool', 'Master', 'Hummer', 'High Performace', 'Better' );

begin

// Set the widths of the rows

case ColNr of

      1 : par.ASet(WPAT_COLWIDTH_PC, 500); // % * 100 !

      2 : par.ASet(WPAT_COLWIDTH_PC, 2500);

      else

      begin

         par.ASet(WPAT_COLWIDTH_PC, 1400);

         par.ASet(WPAT_Alignment, Integer(paralRight));

      end;

end;

 

// Set the text and the cell names and commands

 

if RowNr=1 then // Header Row ------------------------------

begin

    case ColNr of

      1 : ;

      2 : par.SetText('Product');

      3 : par.SetText('Price');

      4 : par.SetText('Amount');

      5 : par.SetText('net');

      6 : par.SetText('+VAT');

      7 : par.SetText('total');

    end;

    par.ASetColor(WPAT_FGColor, $A0A0A0);

    par.ASet(WPAT_ParProtected,1);

    par.ASet(WPAT_Alignment, Integer(paralCenter));

end else

if RowNr=7 then // Footer Row ------------------------------

begin

    par.ADel(WPAT_BorderWidth); // Delete the border width for ALL linese

    par.ASet(WPAT_BorderWidthT, 40); // ANd set the top line to 40 twips

    par.ASetAdd( WPAT_BorderFlags, WPBRD_DRAW_Top); // Add a flag!

    // par.ParentRow.ASet(WPAT_BoxMinHeight, WPCentimeterToTwips(1.5));

    par.ASet(WPAT_SpaceBefore, WPCentimeterToTwips(0.3));

    par.ASet(WPAT_SpaceAfter, WPCentimeterToTwips(0.3));

    par.ASet(WPAT_ParProtected,1);

    case ColNr of

      1 : ;

      2 : ;

      3 : ;

      4 : ;

      5 : begin

            par.ASetStringProp(WPAT_PAR_COMMAND, 'PAR_NET');

          end;

      6 : begin

             par.ASetStringProp(WPAT_PAR_COMMAND, 'PAR_VAT');

          end;

      7 : begin

             par.ASetStringProp(WPAT_PAR_COMMAND, 'PAR_TOTAL');

             par.ASetCharStyle(true, WPSTY_BOLD);

          end;

    end;

 

end else // Data Rows ------------------------------

begin

  case ColNr of

      1 : begin

             par.SetText(IntToStr(RowNr-1));

             par.ASet(WPAT_ParProtected,1);

          end;

      2 : par.SetText(prods[RowNr-1]);

      3 : par.SetText(IntToStr(Random(1000)+1));

      4 : par.SetText(IntToStr(Random(3)+1));

      5 : begin

            par.ASetStringProp(WPAT_PAR_COMMAND, 'left(2)*left(1)');

            par.ASetStringProp(WPAT_PAR_NAME, 'PAR_NET');

            par.ASet(WPAT_ParProtected,1);par

          end;

      6 : begin

             par.ASetStringProp(WPAT_PAR_COMMAND, 'left(1)*0.16');

             par.ASetStringProp(WPAT_PAR_NAME, 'PAR_VAT');

             par.ASet(WPAT_ParProtected,1);

          end;

      7 : begin

             par.ASetStringProp(WPAT_PAR_COMMAND, 'left(2)+left(1)');

             par.ASetStringProp(WPAT_PAR_NAME, 'PAR_TOTAL');

             par.ASet(WPAT_ParProtected,1);

          end;

    end;

end;

end;

 

Note: The commands

             par.ASetStringProp(WPAT_PAR_COMMAND, 'left(2)+left(1)');

             par.ASetStringProp(WPAT_PAR_NAME, 'PAR_TOTAL');

are only usable with WPTools Bundle. They are used to add calculation to a table.

 

 

b) Use TableAdd() and the Rows[] and Cols[] arrays

 

This example appends 2 rows to the current table (a new table is created if necessary) and loads an image in the second cell of the first row.

 

Screen shot of the created table. (Only the first row is visible.)

clip0101

 

procedure TForm1.CreateTableWithImageClick(Sender: TObject);

var tbl: TParagraph;

 obj: TWPTextObj;

 img: TWPOImage;

 imagefilename: string;

 rowoffset : Integer;

begin

// Select the image from file or use a local image

 imagefilename := '';

if SelectImageFile.Checked then

begin

  if OpenPictureDialog1.Execute then

     imagefilename := OpenPictureDialog1.FileName

  else exit;

end;

 

// Create the image object

 img := TWPOImage.Create(WPRichText1); // uses WPObj_Image

try

  if imagefilename = '' then img.Picture.Assign(Image2.Picture)

  else img.LoadFromFile(imagefilename);

except

   img.Free; // We cannot load this image

  raise;

end;

 

// This code is required if we do *not* use the wptblAppendTableAtEnd option.

// since than an existing table is enlarged

 tbl := WPRichText1.Table;

if tbl<>nil then

begin

    rowoffset := tbl.RowCount;

    WPRichText1.ActiveParagraph := tbl.LastChild.ColFirst;

end

else rowoffset := 0;

 

// Create the table and after that modify the cells

//  makes sure a new table is created at the end!

 tbl := WPRichText1.TableAdd(2, 1, [wptblActivateBorders], nil, nil);

 

// Set text of first column

 tbl.Rows[rowoffset+0].Cols[0].SetText(imagefilename);

 

// Create the TWPTextObj (which is the reference to image)

 obj := tbl.Rows[rowoffset+0].Cols[1].AppendNewObject(wpobjImage, false, false, 0);

 obj.ObjRef := img;

 obj.Frame := [wpframeFine];

 

// Set the size of the image

 obj.Width := img.ContentsWidth * 2;

 obj.Height := img.ContentsHeight * 2;

 

// Empty row, no borders - move cursor to first cell

 WPRichText1.ActiveParagraph := tbl.ColFirst;

 tbl := WPRichText1.TableAdd(2, 1, [], nil, nil);

 WPRichText1.ActiveParagraph := tbl.ColFirst;

 

// Format and display changed text

 WPRichText1.Refresh;

end;

 

2) Create a table with a header and footer row which are repeated on each page

clip0118

 

This feature is controlled by the flags paprIsFooter and paprIsHeader in the property TParagraph.par. The property must be set in the row paragraph which is the parent paragraph of a cell. The API TableAdd does this for you.

 

We suggest to use this feature with the flag wpfDontBreakTableRows in FormatOptions.

In any case please set the property wpDisableSpeedReformat.

 

Example code:

 

procedure TForm1.CreateTableCellCallBackHF(RowNr, ColNr: Integer; par: TParagraph);

begin

if RowNr = -1 then // THIS CELL IS IN THE HEADER

begin

   par.ASetColor(WPAT_BGColor, clBtnFace);

  if ColNr = 1 then par.ASet(WPAT_COLWIDTH, WPCentimeterToTwips(1.5))

  else par.SetText('HEADER');

end

else if RowNr = -2 then // THIS CELL IS IN THE FOOTER

begin

   par.ASetColor(WPAT_BGColor, clBtnFace);

  if ColNr = 1 then par.ASet(WPAT_COLWIDTH, WPCentimeterToTwips(1.5))

  else par.SetText('FOOTER');

end else

begin

  if (RowNr and 1) = 0 then par.ASetColor(WPAT_BGColor, clYellow);

  if ColNr = 1 then

  begin

     par.ASetColor(WPAT_BGColor, clBtnFace);

     par.ASet(WPAT_COLWIDTH, WPCentimeterToTwips(1.5));

     par.SetText(IntToStr(RowNr));

  end else

  begin

     par.SetText(IntToStr(FCellNr));

     inc(FCellNr);

  end;

end;

end;

 

procedure TForm1.CreateTableWithHeaderFooterClick(Sender: TObject);

begin

 WPRichText1.Clear;

 FRowCount := 200; // count of rows, excluding header and footer!

WPRichText1.FormatOptions := [wpDisableSpeedReformat, wpfDontBreakTableRows];

 WPRichText1.TableAdd(

  4, FRowCount,

   [wptblActivateBorders,wptblCreateHeaderRow,wptblCreateFooterRow], nil,

  CreateTableCellCallBackHF);

 WPRichText1.Refresh;

end;