This post as been superseded. Please see my new post on the subject.
During my use of the excellent tcpdf library for creating pdf documents with php, I came across an interesting problem when creating a pdf featuring a grid of data. Although I could have use an html grid to present the data, I was trying to avoid the use of html and keep to the Cell(), MultiCell(), Text() etc. methods to render the document.
The content of some of the cells in this particular grid were quite long and so some wrapping of text would (and needed to) occur. The MultiCell method handles this and will wrap the text, expanding accordingly. Now I was trying to make a grid row, so needed all of the cells to be the same height – and there lay the problem – I did not know how high to make the other cells. It was a chicken and egg situation: I needed to know the height of the cell before drawing them but did not know how high they needed to be until after I had drawn them.
I studied the documentation hard but realised that the answer was not to try and generate the cells, borders and all, in one pass. I could achieve what I needed by drawing each row twice – once for the content and once for the borders.
The MultiCell function kindly returns the height that the cell was drawn, so by remembering the maximum value it was when drawing a row of cells, I could then go back and draw the borders to that maximum height:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | foreach($data as $row) { $maxnocells = 0; $cellcount = 0; //write text first $startX = $pdf->GetX(); $startY = $pdf->GetY(); //draw cells and record maximum cellcount //cell height is 6 and width is 80 $cellcount = $pdf->MultiCell(80,6,$row['cell1data'],0,'L',0,0); if ($cellcount > $maxnocells ) {$maxnocells = $cellcount;} $cellcount = $pdf->MultiCell(80,6,$row['cell2data'],0,'L',0,0); if ($cellcount > $maxnocells ) {$maxnocells = $cellcount;} $cellcount = $pdf->MultiCell(80,6,$row['cell3data'],0,'L',0,0); if ($cellcount > $maxnocells ) {$maxnocells = $cellcount;} $pdf->SetXY($startX,$startY); //now do borders and fill //cell height is 6 times the max number of cells $pdf->MultiCell(80,$maxnocells * 6,'','LR','L',0,0); $pdf->MultiCell(80,$maxnocells * 6,'','LR','L',0,0); $pdf->MultiCell(80,$maxnocells * 6,'','LR','L',0,0); $pdf->Ln(); } |
Note that the last parameter I set in MultiCell is set to 0 which means that no new line occurs once a cell is drawn. This means that the cells will appear side-by-side and also means that I need to manually create the new line when I finish drawing the row.
SAw this code .tried implementing it it is not working.please guide me why it is not working.
$data = array();
$data[] = array($dbrow51[‘target_set1’],$dbrow51[‘target_modified1’],$dbrow51[‘target_accomplisment1’]);
foreach($data as $row)
{
$maxnocells = 0;
$cellcount = 0;
//write text first
$startX = $pdf->GetX();
$startY = $pdf->GetY();
//draw cells and record maximum cellcount
//cell height is 6 and width is 80
$cellcount = $pdf->MultiCell(60,6,$cellcount.$row[‘0′],0,’L’,0,0);
if ($cellcount > $maxnocells ) {$maxnocells = $cellcount;}
$cellcount = $pdf->MultiCell(60,6,$cellcount.$maxnocells.$row[‘1′],0,’L’,0,0);
if ($cellcount > $maxnocells ) {$maxnocells = $cellcount;}
$cellcount = $pdf->MultiCell(60,6,$cellcount.$maxnocells.$row[‘2′],0,’L’,0,0);
if ($cellcount > $maxnocells ) {$maxnocells = $cellcount;}
$pdf->SetXY($startX,$startY);
//now do borders and fill
//cell height is 6 times the max number of cells
$pdf->MultiCell(60,$maxnocells * 2,”,’LR’,’L’,0,0);
$pdf->MultiCell(60,$maxnocells * 2,”,’LR’,’L’,0,0);
$pdf->MultiCell(60,$maxnocells * 2,”,’LR’,’L’,0,0);
$pdf->Ln();
}
This worked for me like a charm 🙂
I’ve just released these components, advanced multicell and advanced table in tcpdf.
http://www.interpid.eu/tcpdf-multicell
http://www.interpid.eu/tcpdf-table
It might be what you’re looking for.
thank you very much dan,
you saved a lot of my time, this works very well for my purpose
i have a problem, if a row breaks in 1st page the content overwrites in the next page. Any Solution for that?
OMG!! God Bless You.. Really.. really.. I’ve been stuck
with this word wrap and multicell things for weeks and at last I
find your article. Why didn’t I find this since the first time T_T
doh… Thank you so so so much to you…
thanks man i help i lot, though i do some modification so that i will display the output that i need… thanks again
@fm – This article has been superseded by my newer article, as I realised there were some flaws in this one. Have a read of that one and you will see I have taken into account page breaks in a more comprehensive manner.
there is an error, when text data are printed at end of page, frames are printed at next page. you need to put
if ($pdf->GetPage()!=$startPage) $pdf->SetPage($startPage);
before
$pdf->SetXY($startX,$startY);
and
$startPage=$pdf->GetPage();
after
$startY = $pdf->GetY();
mike and jmmontero , please see my new post on the subject. Hopefully it will work for you.
In response to jmmontero,
“How can I print the same headers on each page using TCPDF?”
Simply define the header parameters:
$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE, PDF_HEADER_STRING);
Set the font:
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, ”, PDF_FONT_SIZE_MAIN));
Set the margin:
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
Then call AddPage() and add your page data.
Excellent and Smart solution!! I took your approach and it worked for me!.
By the way, if you don’t mind I would like to ask you, How can I print the same headers on each page using TCPDF? Your answer will be greatly appreciated.
I appreciate your help.
It seems that there must be a way to maybe extend the class and rewrite the MultiCell function so that borders get painted on every screen. I am trying to create a single/multi-page invoice, and having the borders painted only on some pages is not acceptable.
Wow, yes that is an issue with this method. A quick and dirty answer would be to utilise the max height ($maxh) parameter of multicell. That is a bit brutal however and is not a proper solution. I will have a look at this over the weekend and see what I can come up with, I suspect it affects my implementation too..
Any idea how to do this when a multicell’s content is so large that the cell spans pages? In this case, the value returned by multicell seems to be erroneous, and since the position is now on the last page, only the last page gets borders.
I appreciate any pointers.