Title: Printing a list view
Question: When you've created a program, and have one or many listview (in report mode) and you want to print them, then you want something like this to easily print the contents for the listview more or less like you see it on screen.
Answer:
I've had many request for this function after posting some information about it on the usenet some years ago.
You'll also find the most recent version on http://www.sventore.com/delphi.php
I'll more or less paste in the procedure, and try to explain what it does.
First, I've introduced v and h real. They are not _really_ needed the printing, but it makes everything much easier to place on the paper.
Positioning is static, and fits on a A4, numbers are metric, and converted to printer points by the v and h constants.
I've also used a correction factor of 0.95. This was due to a problem with the clients printer, and should probably be removed. I you get problems with rows stretching lower that the printer canvas, you should try to change this to 1.00 or even more.. There might be a bug in calculation the h factor, but I dont find it at the time.. And this dirty correction worked just fine.. :)
The positioning supports moving to the left, if the title canvas region collide with the date in the top right corner.
In Feb 2002 Sam Francke revised the code for reusability and the version posted here is very much like his revision, so it's fair to give him some credit. He also compiled this sample project (same as attachment):
http://www.sventore.com/getfile.php?Program=PrintListView&Version=1.0
procedure TMainForm.PrintListview(oListView: TListView);
//-----------------------------------------------------
var
pWidth, pHeight, i: Integer;
v, h: Real;
CurItem, iColumnCount: Integer;
//aCols: array[0..50] of Integer; // Delphi 3
aCols: array of Integer; // Delphi 5
iTotColsWidth, iInnerWidth, TopMarg, LinesOnPage, CurLine, TekstHeight, CurCol: Integer;
CurRect: TRect;
CurStr: string;
CurLeft, NumPages, TmpPos: Integer;
begin
if PrintDialog1.Execute then
begin
iColumnCount := oListview.Columns.Count;
//SetLength(aCols, iColumnCount + 1); // + 1 nodig ??? Delphi 5
Printer.Title := 'Listview Print';
Printer.Copies := 1;
Printer.Orientation := poPortrait;
Printer.BeginDoc;
pHeight := Printer.PageHeight;
pWidth := Printer.PageWidth;
v := (pHeight + (2 * GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY))) / (29.7 * 0.95);
//0.95 is a strange correction factor on the clients printer
h := (pWidth + (2 * GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX))) / 21;
// calculate total width
iTotColsWidth := 0;
for i := 0 to iColumnCount - 1 do
iTotColsWidth := iTotColsWidth + oListView.Columns[i].Width;
// calculate space between lMargin and rMargin
aCols[0] := Round(1.5 * h); //left margin ?
aCols[iColumnCount + 0] := pWidth - Round(1.5 * h); //rigth margin ?
iInnerWidth := aCols[iColumnCount + 0] - aCols[0]; // space between margins ?
//calculate start of each column
for i := 0 to iColumnCount - 1 do
aCols[i + 1] := aCols[i] + Round(oListView.Columns[i].Width / iTotColsWidth * iInnerWidth);
TopMarg := Round(2.5 * v);
with Printer.Canvas do
begin
Font.Size := 10;
Font.Style := [];
Font.Name := 'Times New Roman';
Font.Color := RGB(0, 0, 0);
TekstHeight := Printer.Canvas.TextHeight('dummy');
LinesOnPage := Round((PHeight - (5 * v)) / TekstHeight);
NumPages := 1;
// gather number of pages to print
while (NumPages * LinesOnPage) inc(NumPages);
// start
CurLine := 0;
for CurItem := 0 to oListView.Items.Count - 1 do
begin
if (CurLine LinesOnPage) or (CurLine = 0) then
begin
if (CurLine LinesOnPage) then Printer.NewPage;
CurLine := 1;
if Printer.PageNumber = NumPages then
begin
MoveTo(aCols[1], topMarg);
for i := 1 to iColumnCount - 1 do
begin
LineTo(aCols[i], TopMarg + (TekstHeight * (oListView.Items.Count - CurItem + 2)));
MoveTo(aCols[i + 1], topMarg);
end;
end
else
begin
// draw vertical lines between data
for i := 1 to iColumnCount - 1 do
begin
MoveTo(aCols[i], topMarg);
LineTo(aCols[i], TopMarg + (TekstHeight * (LinesOnPage + 1)));
end;
end;
Font.Style := [fsBold];
// print column headers
for i := 0 to iColumnCount - 1 do
begin
TextRect(Rect(aCols[i] + Round(0.1 * h), TopMarg - Round(0.1 * v), aCols[i + 1] - Round(0.1 * h)
, TopMarg + TekstHeight - Round(0.1 * v)), ((aCols[i + 1] - aCols[i]) div 2) +
aCols[i] - (TextWidth(oListview.Columns.Items[i].Caption) div 2),
TopMarg - Round(0.1 * v), oListview.Columns.Items[i].Caption);
//showmessage('print kolom: '+IntToStr(i));
end;
// draw horizontal line beneath column headers
MoveTo(aCols[0] - Round(0.1 * h), TopMarg + TekstHeight - Round(0.05 * v));
LineTo(aCols[iColumnCount] + Round(0.1 * h), TopMarg + TekstHeight - Round(0.05 * v));
// print date and page number
Font.Size := 8;
Font.Style := [];
TmpPos := (TextWidth('Date: ' + DateToStr(Date) + ' Page: ' +
IntToStr(Printer.PageNumber) + ' / ' + IntToStr(NumPages))) div 2;
TmpPos := PWidth - Round(1.5 * h) - (TmpPos * 2);
Font.Size := 8;
Font.Style := [];
TextOut(TmpPos, Round(0.5 * v), 'Date: ' + DateToStr(Date) +
' Page: ' + IntToStr(Printer.PageNumber) + ' / ' + IntToStr(NumPages));
// print report title
Font.Size := 18;
if TmpPos TextOut((PWidth - TextWidth(EditReport.Text)) div 2, Round(1 * v), EditReport.Text)
else
TextOut(Round(3 * h), Round(1 * v), EditReport.Text);
Font.Size := 10;
Font.Style := [];
end;
CurRect.Top := TopMarg + (CurLine * TekstHeight);
CurRect.Bottom := TopMarg + ((CurLine + 1) * TekstHeight);
// print contents of Listview
for CurCol := -1 to iColumnCount - 2 do
begin
CurRect.Left := aCols[CurCol + 1] + Round(0.1 * h);
CurRect.Right := aCols[CurCol + 2] - Round(0.1 * h);
try
if CurCol = -1 then
CurStr := oListView.Items[CurItem].Caption
else
CurStr := oListView.Items[CurItem].SubItems[CurCol];
except
CurStr := '';
end;
CurLeft := CurRect.Left; // align left side
// write string in TextRect
TextRect(CurRect, CurLeft, CurRect.Top, CurStr);
end;
Inc(CurLine);
end;
end;
Printer.EndDoc;
end;
end;