Customized Printing in Delphi

Delphi provides modern full text and graphics printing facility. We can print texts, images and shapes in different formats by using several Delphi classes and members. We can also access printers installed on system and can change their properties Print and printer setup dialog in Delphi. Delphi provides TPrintDialog and TPrinterSetupDialog components to confirm printing and to set printer properties. Delphi also provides Printer object which provides functions to access printers details and to print any text or image on canvas. In this blog I will show how to use TPrintDialog and TPrinterSetUpDialog. I will also explain with examples on how to print TRichedit text, how to print TListView data and how to print custom data on Printer.Canvas.

Using Print dialog and Printer Setup dialog
It is a good practice that we display the printer dialog so that user can control printing. We will show a print dialog that allows the user to select all pages, or a range of pages. We can also set printer properties using Printer setup dialog.


TPrinterSetupDialog
TPrinterSetupDialog is used to change printer and paper options.

object PrinterSetupDialog1: TPrinterSetupDialog
  Left = 184
  Top = 160
End

Execute the dialog.

procedure TForm1.btnPrinterSetupClick(Sender: TObject);
begin
  if PrinterSetupDialog1.Execute then
  begin
    ShowMessage('Printer SetUp is done.');
  end;
end;


TPrintDialog
TPrintdialog component is used to show a dialog for select printer and to change their options. It also allows users to cancel the print.

object PrintDialog1: TPrintDialog
  Left = 184
  Top = 80
End

Set printer options

//allowed pages//
printdialog1.MinPage := 1;
printdialog1.MaxPage := 10;

//page range to print//
printdialog1.FromPage := 5;
printdialog1.ToPage := 10;
//allow page range selection//
printdialog1.Options := [poPageNums];

Execute the dialog.

procedure TForm1.btnPrintClick(Sender: TObject);
begin
  if PrintDialog1.Execute then
  begin
    ShowMessage('Print is done.');
  end;
end;


How to print text or image ?
For normal text we can use TRichEdit control or we can use Printer.Canvas for custom printing. But for Image we can use Report builder or we can use Printer.Canvas. 

So lets first see how to print texts using TRichedit control.

Print TRichedit Text
Printing texts using TRichEdit is very easy, we just need to call Richedit.Print method and what ever the texts in TRichedit will be printed.

First put a TRichedit control on a form and set some lines data. We can change the font of TRichedit control's text as needed. Then on button click just call RichEdit.Print method.

procedure TForm1.btnPrintClick(Sender: TObject);
begin
  if PrintDialog1.Execute then
  begin
    RichEdit1.Print('Print Rich Edit Data');

    ShowMessage('Print is done.');
  end;

end;


I selected XPS Viewer for print.


Using of Printer object 
Printer object provides canvas to draw texts or images. It also provides lots of procedures to print the drawn data in canvas. Writing directly to the printer's canvas provides more control than using someone else's components.

To use Printer object add Printers unit to your uses clause and use the Printer function to access the global object of TPrinter. Following are some important functions of TPrinter object.

Printer.BeginDoc starts the print job
Printer.EndDoc stops the print job and sends it to the printer
Printer.Title sets print job title
Printer.Orientation sets printer page orientation
Printer.Copies set number of copies be printed
Printer.NewPage create and forces a new page
Printer.Canvas is used to generate the output page
Printer.Printers returns list of printers installed on system
Printer.Abort aborts printing job
Printer.Printing returns as printing going on or finished
Printer.Aborted printing is aborted or not

So first lets see with a simple text print and then we will how to print images or shapes.

Print Text using Printer.Canvas
Here we will try to print a Memo control’s text. So I have put a TMemo control and a button control. On button click I am printing texts in memo with using Delphi Printer object.

procedure TForm1.btnPrintClick(Sender: TObject);
var
  rectPage: TRect;
  sText: string;
begin
  if PrintDialog1.Execute then
  begin
    rectPage := Rect(0, 0, Printer.PageWidth, Printer.PageHeight);
    with Printer do
    begin
      //start printing
      BeginDoc;

      sText := memo1.Text;
//setting font details//
      Canvas.Font.Name := 'Verdana';
      Canvas.Font.Size := 11;
      Canvas.Font.Color := clRed;
//draws the text to print//
      Canvas.TextRect(rectPage, sText, [tfWordBreak]);

      //finish printing
      EndDoc;
    end;

    ShowMessage('Print is done.');
  end;

end;


Print Image using Printer.Canvas
Now I am going to show you how to print an image from a file. First I will put a TImage control and will load an image from file with writing code and then will print the image by using Printer object.

procedure TForm1.btnPrintClick(Sender: TObject);
var
  rectPage: TRect;
  image1: TBitmap;
begin
  if PrintDialog1.Execute then
  begin
    rectPage := Rect(0, 0, Printer.PageWidth, Printer.PageHeight);
    with Printer do
    begin
      //start printing
      BeginDoc;
      image1 := TBitmap.Create;
      image1.LoadFromFile('C:\jitendra\clock.bmp');
      Canvas.StretchDraw(Rect(500, 1000, 1500, 2000), image1);
      image1.Free;
      //finish printing
      EndDoc;
    end;
    ShowMessage('Print is done.');
  end;
end;


Print Line and Shapes using Printer.Canvas
We can draw any kind of shape on Printer.Canvas and can print that drawn shape. More about drawing shapes in Delphi.

procedure TForm1.btnPrintClick(Sender: TObject);
var
  rectPage: TRect;
begin
  if PrintDialog1.Execute then
  begin
    rectPage := Rect(0, 0, Printer.PageWidth, Printer.PageHeight);
    with Printer do
    begin
      //start printing
      BeginDoc;
      Canvas.Pen.Width := 3;
      Canvas.Pen.Color := clBlue;
      Canvas.MoveTo(500, 2200);
      Canvas.LineTo(rectPage.Width-500, 2200);

      Canvas.Brush.Color := clRed;
      Canvas.Rectangle(1000, 2500, 2000, 3500);

      Canvas.Brush.Color := clYellow;
      Canvas.Ellipse(1000, 3000, 2000, 4000);

      //finish printing
      EndDoc;
    end;

    ShowMessage('Print is done.');
  end;
end;


Now I am putting all in one…

procedure TForm1.btnPrintClick(Sender: TObject);
var
  rectPage: TRect;
  rectText: TRect;
  sText: string;
  sReportHeader: string;
  image1: TBitmap;
begin
  if PrintDialog1.Execute then
  begin
    rectPage := Rect(0, 0, Printer.PageWidth, Printer.PageHeight);
    with Printer do
    begin
      //start printing
      BeginDoc;

      sReportHeader := 'Report Header';
      sText := RichEdit1.Lines.Text;
      Canvas.Font.Name := 'Verdana';
      Canvas.Font.Size := 11;

      Canvas.Font.Color := clBlack;
      Canvas.Font.Style := [fsBold];
      Canvas.TextRect(rectPage, (rectPage.Width-Canvas.TextWidth(sReportHeader)) div 2,
                                                10, sReportHeader);

      Canvas.Font.Color := clRed;
      Canvas.Font.Style := [];
      rectText := Rect(100, 300, rectPage.Width-200, 1000);
      Canvas.TextRect(rectText, sText, [tfWordBreak]);

      image1 := TBitmap.Create;
      image1.LoadFromFile('C:\jitendra\clock.bmp');
      Canvas.StretchDraw(Rect(500, 1000, 1500, 2000), image1);
      image1.Free;

      Canvas.Pen.Width := 3;
      Canvas.Pen.Color := clBlue;
      Canvas.MoveTo(500, 2200);
      Canvas.LineTo(rectPage.Width-500, 2200);

      Canvas.Brush.Color := clRed;
      Canvas.Rectangle(1000, 2500, 2000, 3500);

      Canvas.Brush.Color := clYellow;
      Canvas.Ellipse(1000, 3000, 2000, 4000);

      //finish printing
      EndDoc;
    end;

    ShowMessage('Print is done.');
  end;
end;


Print TListView data using Printer.canvas
Here in following example I showed how to print Listview data and also added NewPage to print another ListView control data. I have put 2 Listview control, 2 Button control and on button click I am filling Listview data. And on Print button click I am printing the filled data.

So lets see…


//fill employee data//
procedure TForm1.btnLoadEmpdataClick(Sender: TObject);
begin
  with listviewEmp do
  begin
    with Items.Add do
    begin
      Caption := '1';
      SubItems.Add('Messi');
    end;
    with Items.Add do
    begin
      Caption := '2';
      SubItems.Add('Sachin');
    end;
    with Items.Add do
    begin
      Caption := '3';
      SubItems.Add('Phillip');
    end;
    with Items.Add do
    begin
      Caption := '4';
      SubItems.Add('Mike');
    end;
    with Items.Add do
    begin
      Caption := '5';
      SubItems.Add('Shane');
    end;
    with Items.Add do
    begin
      Caption := '6';
      SubItems.Add('Ramos');
    end;
    with Items.Add do
    begin
      Caption := '7';
      SubItems.Add('Polluck');
    end;
    with Items.Add do
    begin
      Caption := '8';
      SubItems.Add('Jorge');
    end;
    with Items.Add do
    begin
      Caption := '9';
      SubItems.Add('Gayle');
    end;
    with Items.Add do
    begin
      Caption := '10';
      SubItems.Add('John');
    end;
  end;
end;

//fill city – country data//
procedure TForm1.btnLoadCitydataClick(Sender: TObject);
begin
  with listviewCity do
  begin
    with Items.Add do
    begin
      Caption := 'Delhi';
      SubItems.Add('India');
    end;
    with Items.Add do
    begin
      Caption := 'Beijing';
      SubItems.Add('China');
    end;
    with Items.Add do
    begin
      Caption := 'Denver';
      SubItems.Add('USA');
    end;
    with Items.Add do
    begin
      Caption := 'London';
      SubItems.Add('UK');
    end;
    with Items.Add do
    begin
      Caption := 'Sydney';
      SubItems.Add('Australia');
    end;
    with Items.Add do
    begin
      Caption := 'Captown';
      SubItems.Add('S. Africa');
    end;
    with Items.Add do
    begin
      Caption := 'Kinsasha';
      SubItems.Add('Congo');
    end;
    with Items.Add do
    begin
      Caption := 'Timphu';
      SubItems.Add('Bhutan');
    end;
    with Items.Add do
    begin
      Caption := 'Paris';
      SubItems.Add('France');
    end;
    with Items.Add do
    begin
      Caption := 'Toronto';
      SubItems.Add('Canada');
    end;
  end;
end;


On Print click…

procedure TForm1.btnPrintClick(Sender: TObject);
var
  sText: string;
  sReportHeader: string;
  image1: TBitmap;
  i: Integer;
  iTop: Integer;
begin
  if PrintDialog1.Execute then
  begin
    with Printer do
    begin
      //start printing
      BeginDoc;

      Canvas.Font.Size := 15;
      Canvas.Font.Color := clRed;
      Canvas.Font.Style := [fsBold];

      sReportHeader := 'Employee Details';
      Canvas.TextOut((Printer.PageWidth-Canvas.TextWidth(sReportHeader)) div 2, 100, sReportHeader);

      Canvas.MoveTo(200, 500);
      Canvas.LineTo(Printer.PageWidth-200, 500);

      Canvas.Font.Size := 12;
      Canvas.Font.Color := clBlue;
      Canvas.Font.Style := [fsBold];

      Canvas.TextOut(400, 600, listviewEmp.Column[0].Caption);
      Canvas.TextOut(1000, 600, listviewEmp.Column[1].Caption);

      Canvas.MoveTo(200, 800);
      Canvas.LineTo(Printer.PageWidth-200, 800);

      Canvas.Font.Size := 10;
      Canvas.Font.Color := clBlack;
      Canvas.Font.Style := [];
      iTop := 900;
      for I := 0 to listviewEmp.Items.Count-1 do
      begin
        Canvas.TextOut(400, iTop, listviewEmp.Items[i].Caption);
        Canvas.TextOut(1000, iTop, listviewEmp.Items[i].SubItems[0]);
        iTop := iTop + 250;
      end;

      iTop := iTop+250;
      Canvas.MoveTo(200, iTop);
      Canvas.LineTo(Printer.PageWidth-200, iTop);

      Canvas.TextOut((Printer.PageWidth-Canvas.TextWidth(sReportHeader)) div 2, iTop + 100, DateToStr(Now)+' - Page:'+IntToStr(PageNumber));

      NewPage;

      Canvas.Font.Size := 15;
      Canvas.Font.Color := clRed;
      Canvas.Font.Style := [fsBold];

      sReportHeader := 'City - Country Details';
      Canvas.TextOut((Printer.PageWidth-Canvas.TextWidth(sReportHeader)) div 2, 100, sReportHeader);

      Canvas.MoveTo(200, 500);
      Canvas.LineTo(Printer.PageWidth-200, 500);

      Canvas.Font.Size := 12;
      Canvas.Font.Color := clBlue;
      Canvas.Font.Style := [fsBold];

      Canvas.TextOut(400, 600, listviewCity.Column[0].Caption);
      Canvas.TextOut(2000, 600, listviewCity.Column[1].Caption);

      Canvas.MoveTo(200, 800);
      Canvas.LineTo(Printer.PageWidth-200, 800);

      Canvas.Font.Size := 10;
      Canvas.Font.Color := clBlack;
      Canvas.Font.Style := [];
      iTop := 900;
      for I := 0 to listviewCity.Items.Count-1 do
      begin
        Canvas.TextOut(400, iTop, listviewCity.Items[i].Caption);
        Canvas.TextOut(2000, iTop, listviewCity.Items[i].SubItems[0]);
        iTop := iTop + 250;
      end;

      iTop := iTop+250;
      Canvas.MoveTo(200, iTop);
      Canvas.LineTo(Printer.PageWidth-200, iTop);

      Canvas.TextOut((Printer.PageWidth-Canvas.TextWidth(sReportHeader)) div 2, iTop + 100, DateToStr(Now)+' - Page:'+IntToStr(PageNumber));

      //finish printing
      EndDoc;
    end;

    ShowMessage('Print is done.');
  end;
end;



Cancel a Printing Job
Sometime while printing a complexity and larger size than simple one then it may be important to provide a Cancel print option to user so that User can cancel the print for unwanted printing.

procedure TForm1.btnCanelPrintClick(Sender: TObject);
begin
   // Now user has pressed cancel, we abort the printing //
   if Printer.Printing then
   begin
     Printer.Abort;
     ShowMessage('Printing aborted');
   end;
end;

Get Printers list installed in our System
Printer.Printers property returns list of printers installed in our system. As it’s a TStrings type property we can assign the property to combobox property. In following example, on form create I am filling combobox items with Printers list.

procedure TForm1.FormCreate(Sender: TObject);
begin
  ComboBox1.Items.Assign(Printer.Printers);
end;



To get default printer set on our system
Printer.PrinterIndex returns default printer set on our system.

  ComboBox1.ItemIndex := Printer.PrinterIndex; 

Print existing files from Delphi using ShellExecute
We can use ShellExecute procedure to print existing PDF, DOC, XLS, HTML, RTF, DOCX, TXT documents. ShellExecute can be used launch application, open Windows Explorer or prints the specified file. ShellExecute always uses the default printer for the "print" action.

ShellExecute: Print

ShellExecute(Handle, 'print', PChar('c:\jitendra\file1.doc'), nil, nil, SW_HIDE) ;

Using the above call, document " file1.doc" located on the root of the C drive will be sent to the Windows default printer and will be printed.

ShellExecute: PrintTo

Print a file to a specific printer. So for that, first we are adding list of printers to a combobox and then we will print the file to selected printer. Drop a ComboBox on a form. Name it "cboPrinter". Set Style to csDropDownEdit. 

On form create

//have available printers in the combo box
cboPrinter.Items.Assign(printer.Printers);

//pre-select the default / active printer
cboPrinter.ItemIndex := printer.PrinterIndex;

uses 
   shellapi, printers;
.....
procedure PrintDocument(const documentToPrint : string) ;
var
  printCommand : string;
  printerInfo : string;
  Device, Driver, Port: array[0..255] of Char;
  hDeviceMode: THandle;
begin
  if Printer.PrinterIndex = cboPrinter.ItemIndex then
  begin
    printCommand := 'print';
    printerInfo := '';
  end;
  else
  begin
    printCommand := 'printto';
    Printer.PrinterIndex := cboPrinter.ItemIndex;
    Printer.GetPrinter(Device, Driver, Port, hDeviceMode) ;
    printerInfo := Format('"%s" "%s" "%s"', [Device, Driver, Port]) ;
  end;
  ShellExecute(Application.Handle, PChar(printCommand), PChar(documentToPrint), PChar(printerInfo), nil, SW_HIDE) ;
end;


Comments

  1. Hey,
    This information has been very useful, This blog has provided me proper knowledge and understanding regarding the issue, I have tried this printing accordingly as mentioned and is impressed by the result and the different ways that this printing can be done.Though at the start there was an unknown error called lexmark 900 firmware error, this error has been solved by switching the printer off and letting it delete and reset the memory and then switching it for solving the issue.

    ReplyDelete
  2. Initially I was facing trouble while using Epson printer, but figured out it to be a driver issue, directly related to error code 0x97
    which was responsible for the issue.

    ReplyDelete
  3. Being a tech professional I got this blog is very informative it is based on Customized Printing in Delphi, which I found very relevant. If your printer do issue and
    canon printer not printing black then you can check it out.

    ReplyDelete
  4. Lovely blog! The customized fashion is intelligent trendy, and at the same time comfortable.

    Garmentprinting

    ReplyDelete
  5. Many thanks for taking the time to discuss this, I really feel strongly about it and love learning much more on this topic.I hope we get new updates related to the blog.
    Customised Drinkware

    ReplyDelete
  6. My Testimony Hello everyone. Am here to testify how I got my loan from Mr. Benjamin after I applied several times from various loan lenders who promised to help but they never gave me the loan. Until a friend of mine introduced me to Mr.Benjamin Lee promised to help me and indeed he did as he promised without any form of delay.I never thought there are still reliable loan lenders until I met Mr. Benjamin Lee, who indeed helped with the loan and changed my belief. I don't know if you are in any way in need of a genuine and urgent loan, Be free to contact Mr. Benjamin via WhatsApp +1-989-394-3740 and  his email: Lfdsloans@outlook.com thank you. 

    ReplyDelete
  7. We are providing UK Printing services of printing the HR manuals and documents. Online ordering service is available 24/7 to save your time and effort.

    ReplyDelete
  8. Amazing product thanks for sharing with us It is very informative. If you need any type of boxes you can visit the link.
    Candy packaging Connecticut
    custom made Bath Bomb boxes

    ReplyDelete
  9. Embroidery Denver - Rocky Mountain Apparel in Denver, Colorado, has been producing high quality screen printing, embroidery, promotional products, banners and graphic design services for over 25 years to Colorado. To contact Rocky Mountain Apparel or to obtain a free quote, please complete the fields below and click SUBMIT.

    ReplyDelete
  10. I like the post Its has nice article It's really effective and very impressive, We hope this information will help everyone.Corporate Gifts Printing Services in Bangalore

    ReplyDelete
  11. Thank you for your post, myself very happy to read it because it can give me more insight, thanks.Perfect Cut Vinyl

    ReplyDelete
  12. Pretty good useful information you shared with us.About the background of printer and also functions of a printer

    ReplyDelete
  13. The cultural sensitivity and awareness you bring to your topics are commendable. You navigate diverse subjects with respect and insight.

    Marble Floor Polishing in Dubai

    ReplyDelete
  14. Thanks for the insightful post! The capabilities of Delphi for printing are fantastic, especially when it comes to producing personalised corporate gifts
    and bulk corporate gifts I’m eager to see how you’ll showcase TPrintDialog and TPrinterSetupDialog in action. It sounds like a valuable resource for custom printing needs!

    ReplyDelete
  15. This blog is absolutely fantastic! The content is not only informative but also engaging. I really appreciate the effort and detail put into each post. Highly recommended for anyone looking for valuable insights. For more great content, feel free to visit my website as wellDigital Marketing Services in Pakistan

    ReplyDelete

Post a Comment

Popular posts from this blog

ShellExecute in Delphi

MS Excel Automation in Delphi

Drawing Shapes in Delphi