eDocEngine VCL
Create documents and reports in 18 formats
Compatibility
Delphi C++Builder

A Delphi Mail-Merge Example With eDocEngine VCL 3

Using not just fake names and addresses, but also aliens, super heroes and rocks from outer space.
By V. Subhash

When you create a document with eDocEngine, you can use placeholders in the text strings that are rendered on a page. These placeholders are substituted with actual values at run time. Built-in or pre-defined placeholders are substituted by the document-creation engine automatically. Custom or user-defined placeholders need to be substituted by you in the code. To perform this substitution, you need to handle the engine's OnCalcVariables event. The function type of the event handler is:

TgtOnCalcVariablesEvent = procedure (Sender: TgtCustomDocumentEngine;
Variable: String; // Current placeholder
var Value: String) // Value for the placeholder of object;

The OnCalcVariables event is called every time a user-defined placeholder is written to the document. In this article, we will see a mail-merge example built around it.

For the stationery, we will use a simple postcard. We then render boilerplate content on the card - address on the front and message on the reverse. To make it look all authentic, we will also print a stamp using an image. In a real office scenario, you will have to render a box with the text "Affix stamp here". Here we go.

  1. Open the IDE and create a VCL forms application project.
  2. From the tool palette, drop the following controls on the form.
    1. TDBGrid
    2. TDataSource
    3. TADODataSet
    4. TgtPDFEngine
    5. Tbutton
  3. Ensure that the NorthWind sample Access database is in the project directory. You may use any other database but you will have to make appropriate changes to the code given below.
  4. Set the DataSource property of the TDBGrid object is set to the TDataSource object.
  5. Set the DataSet property of the TDataSource object to the TADODataSet object.
  6. Set the following click-event handler for the button. In the textouts, the placeholders need to be delimited by <% and %>.
    procedure TForm13.Button1Click(Sender: TObject);
    var
      I, N: Integer;
      Bitmap1: TBitmap;
    begin
      // Create an image
      Bitmap1 := TBitmap.Create;
      Bitmap1.LoadFromFile('UFO_Stamp.bmp');
    
      with gtPDFEngine1 do begin
    
        Preferences.ShowSetupDialog := False;
        Preferences.CalculateVariables := true;
        Preferences.ProcessAfterEachPage := true;
    
        Page.PaperSize := Custom;
    
    
        OnCalcVariables := gtPDFEngine1CalcVariablesEventHandler;
        FileName := 'edocengine_mail_merge.pdf';
        Font.Size := 18;
        Page.Width := 8;
        Page.Height := 4;
    
        BeginDoc;
        N := DBGrid1.DataSource.DataSet.RecordCount;
        DBGrid1.DataSource.DataSet.First;
    
        for I := 1 to N do begin
          // Render address on post card
          DrawImage(5.6,0.2, Bitmap1);
          Font.Size := 18;
          Font.Color := clBlack;
          Font.Style := [];
          TextOut(1.5,1.4, 'To');
          TextOut(2,1.8, '<%Name%>');
          TextOut(2,2.2, '<%Address%>');
          TextOut(2,2.6, '<%Country%>');
          Font.Size := 9;
          Font.Style := [fsItalic];
          Font.Color := clRed;
          TextOut(0.2,3.3,'If undelivered, please return to:');
          TextOut(0.3,3.45,'Superdude');
          TextOut(0.3,3.6,'Crypton');
    
          // Render message on post card
          Font.Size := 18;
          Font.Color := clBlack;
          Font.Style := [];
          NewPage;
          TextOut(0.5,0.3, 'Dear Mr./Ms. <%Name%>,');
          TextOut(0.5,0.8, 'Last month, we received a rare container shipment of');
          TextOut(0.5,1.2, 'cryptonite. As a loyal member of <%City%> Superdude ');
          TextOut(0.5,1.6, 'Fan Club, you are eligible for a vial of this space debris');
          TextOut(0.5,2,   'engraved with your name "<%Name%>."');
          TextOut(0.5,2.4, 'Please find it enclosed with this card. Thank you.');
          TextOut(0.5,3,   'V. Subhash');
          TextOut(0.5,3.4, 'President, Intergalactic Superdude Fans Association');
    
          if I <> N then begin
            NewPage;
          end;
          DBGrid1.DataSource.DataSet.Next;  
        end;
        EndDoc;
        Close;
      end;
    end;
    
  7. Set the following OnCalcVariables event handler for the PDF engine.
    // OnCalcVariables eventhandler that supplies values
    // for placeholders
    procedure TForm13.gtPDFEngine1CalcVariablesEventHandler(
                 Sender: TgtCustomDocumentEngine;
                 Variable: String;
                 var Value: String);
    begin
      // Provide values for the placeholders
      if Variable = 'Name' then begin
        Value := DBGrid1.DataSource.DataSet.FieldByName('CONTACTNAME').Value;
      end;
      if Variable = 'Address' then begin
        Value := Trim(DBGrid1.DataSource.DataSet.FieldByName('ADDRESS').Value) +
                 ', ' +
                 DBGrid1.DataSource.DataSet.FieldByName('CITY').Value;
      end;
      if Variable = 'City' then begin
        Value := Trim(DBGrid1.DataSource.DataSet.FieldByName('CITY').Value);
      end;
      if Variable = 'Country' then begin
        Value := DBGrid1.DataSource.DataSet.FieldByName('COUNTRY').Value;
      end;
    end;
    
  8. Set the dataset in the form-creation event. This allows you to keep the template intact but easily change the dataset when required.
    procedure TForm13.FormCreate(Sender: TObject);
    begin
    
      ADODataSet1.ConnectionString :=
        'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' +
        GetCurrentDir +
        '\Input_Docs\FPNWIND.MDB;Persist Security Info=False';
    
      ADODataSet1.CommandText :=
        'SELECT CONTACTNAME, ADDRESS, CITY, COUNTRY ' +
        'FROM CUSTOMERS';
    
      ADODataSet1.Active := true;
    
    end;
    
  9. Run the form and click the button.

And finally, here is the merged output.

Improvement Suggestion

The Customers table in the NorthWind database does not contain an e-mail address column. If you have a table that has one, then you could modify the code to create a separate PDF for each customer and then automatically send that document to the customer's e-mail address. To do this, you will have to

  1. Call BeginDoc and EndDoc inside the For loop rather than outside.
  2. Set the TgtPDFEngine.Preferences.EmailAfterCreate property to True.
  3. Specify e-mail settings in the TgtPDFEngine.EmailSettings property.
  4. Specify the recipient's e-mail address in the handler for the TgtPDFEngine.OnEmail event.

---o0O0o---

Our .NET Developer Tools
XtremeDocumentStudio .NET

Multi-format document-processing component suite for .NET developers.

PDFOne .NET

A .NET PDF component suite to create, edit, view, print, reorganize, encrypt, annotate, and bookmark PDF documents in .NET applications.

Our Delphi/C++Builder developer tools
XtremeDocumentStudio Delphi

Multi-format document-processing component suite for Delphi/C++Builder developers, covering both VCL and FireMonkey platforms.

eDocEngine VCL

A Delphi/C++Builder component suite for creating documents in over 20 formats and also export reports from popular Delphi reporting tools.

PDFtoolkit VCL

A Delphi/C++Builder component suite to edit, enhance, view, print, merge, split, encrypt, annotate, and bookmark PDF documents.

Our Java developer tools
XtremeDocumentStudio (for Java)

Multi-format document-processing component suite for Java developers.

PDFOne (for Java)

A Java PDF component suite to create, edit, view, print, reorganize, encrypt, annotate, bookmark PDF documents in Java applications.

Our Platform-Agnostic Cloud and On-Premises APIs
StarDocs

Cloud-hosted and On-Premises REST-based document-processing and document-viewing APIs

Privacy | Legal | Feedback | Newsletter | Blog | Resellers © 2002-2017 Gnostice Information Technologies Private Limited. All rights reserved.