Home General
New Blog Posts: Merging Reports - Part 1 and Part 2

PDF Forms

edited December 2011 in General
Hi

Report Builder 14.01 Enterprise and Delphi

I am after some suggestions on how to do something. I am wanting to create
PDF Forms for clients to enter and submit data. I know how to do the
majority of the tasks but am not sure on one aspect (the position of the
input boxes)

The form is to contain a list of Photocopiers that a client has and prompts
the user to enter the latest meter readings. Each client could have 1 or
more photocopiers and each photocopier could have multiple meters (B&W,
Colour etc). Instructions on how to take the reading need to be displayed
and these could be variable in length (ie dynamic detail band is the ideal).
The design of the report is not a problem. There would be a detail band for
each Meter which has its own unique serial number. The report is saved to
pdf file. My application then takes the pdf file and using GNostices
PDFtoolkit v4 adds Text Input boxes (one for each meter) and a Submit
button. This modified pdf file is then emailed to the client. The client
opens the pdf form (in Adobe) fills in the input boxes and then presses the
Submit button that emails the inputted data in xml format back to the
originator. The xml file is then read and the clients meter readings
transferred back into my application. I have developed and tested that bit.
I am also looking to use Add In Express to automate the reading of the
emails as there are likely to be hundreds of them, but that is another
issue.

My problem is knowing where to exactly position the GNostice Text Input
boxes on the pdf form i have generated with ReportBuilder. How can i feed
back the position and page number of each Detail Band ideally with the
corresponding unique meter serial number? If the detail band was static i
know that i could pre-determine where everything should go but it might not
work if page layouts change, footers increase etc. This same application
is used my multiple users all who have slightly differing requirements. I
also have to know the physical location of the summary band as the Submit
button needs to be placed in this area.

I am loading the Report from file and using DBPipelines. I would appreciate
any help and suggestions. The ideal of course is for Digital Metaphors to
add all this functionality in a new release but i have to assume that this
is not just about to happen!

Regards

Tim Murfitt

Comments

  • edited December 2011
    Tim,

    PDF form fields would be a useful feature and is on our list of possible
    enhancements to research for a later release.

    Rather than trying to figure out band position etc., try using the
    drawcommands themselves to give you the exact position of a component on
    a page. A drawcommand's position is in microns, which can easily be
    converted to points. Since the page size is the same, you could use the
    drawcommand measurements of a report component to position your form
    fields in the PDF document.

    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • edited December 2011
    Nico

    I am glad that you are considering this for a future release.

    I had already guessed it would be best to get the position of an invisible
    shape object (or similar) where my input box is to go but how do i get that
    into my delphi application. That is the bit i am not sure how to do. Can
    you give me a little bit of guidance. Do i look at the report's objects
    from delphi (and if so what is the best way) or do i do something (write to
    a file?) from within the Report. I am not sure where to start.

    Thanks

    Tim




  • edited December 2011
    Hi Tim,

    Ideally you will want to place a visible component marking the spot you
    would like the form field to be. This could be a white rectangle or
    perhaps a label with just a space as the text value.

    Once this is done, you can use the OnDrawCommandCreate event of the
    component to determine where on the page this component is being drawn.
    Use the aDrawCommand.Left, Top, etc. properties. Once you have this
    information, you should be able to manually add these form fields to the
    PDF output at the proper locations.

    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • edited December 2011
    Nico

    Thanks for your response. I have got it working (test code shown below)
    but i have a few questions.

    What is the best way to link the DrawCommandCreate with the actual object.
    I did it in code (ppShape1.OnDrawCommandCreate :=
    ppShape1DrawCommandCreate;) but in the Delphi Code samples in rbWiki you
    dont do this. It is not obvious how you did it other than opening the
    DelphiForm.dfm file and adding the line in there. Is there another way. I
    found that unless i linked the object event with the procedure it would not
    fire.

    I would really like to load the Report from file as there will be
    customisation of the layout from user to user. The problem i then have is
    that the report objects i refer to in the code below do not then exist and
    the code will not compile. Is it possible to do this? If not i think that
    the solution would be to put the customisable elements in one or more sub
    reports which are then loaded at run time from file leaving the core element
    and its objects all exposed from the outset. What do you think / suggest?


    Thanks

    Tim




    Extract of Delphi Code. The code is for testing purposes and not the
    finished article. It does however work!

    var
    FormAcroLocate: TFormAcroLocate;
    InputArray : Array[1..9,1..5] of Variant; // The InputArray is used to
    record where the various Input boxes need to be positioned.
    lNoMeters,lSubmitpageNo,lSubmitTopPos,lSubmitLeftPos : Integer;

    implementation

    {$R *.dfm}

    procedure TFormAcroLocate.button1Click(Sender: TObject);
    var SiteNo : String;
    begin
    SiteNo := 'T006270';
    with AdsQuery1 do begin
    Close;
    Unprepare;
    Params[0].asString := SiteNo;
    Prepare;
    Open;
    lNoMeters := RecordCount;
    end;
    ppShape1.OnDrawCommandCreate := ppShape1DrawCommandCreate;
    ppShape2.OnDrawCommandCreate := ppShape2DrawCommandCreate;
    ppReport1.ShowPrintDialog := False;
    ppReport1.DeviceType := 'PDF';
    ppReport1.TextFileName := SiteNo + '.pdf';
    ppReport1.Print;
    CreateAcroForm;
    AdsQuery1.Close;
    end;



    procedure TFormAcroLocate.ppShape1DrawCommandCreate(Sender, aDrawCommand:
    TObject);
    var
    lDrawTextCommand: TppDrawText;
    lTopPosInMicrons, lLeftPosInMicrons, lPageNo, lRecNo : Integer;
    lMeterNo : String;
    begin
    lRecNo := ppDBCalc1.Value;
    lMeterNo := ppDBText2.FieldValue;
    lPageNo := ppReport1.AbsolutePageNo;
    lDrawTextCommand := TppDrawText(aDrawCommand);
    lTopPosInMicrons := lDrawTextCommand.Top;
    lLeftPosInMicrons := lDrawTextCommand.Left;
    InputArray[lRecNo,1] := lRecNo;
    InputArray[lRecNo,2] := lMeterNo;
    InputArray[lRecNo,3] := lPageNo;
    InputArray[lRecNo,4] := lTopPosInMicrons;
    InputArray[lRecNo,5] := lLeftPosInMicrons;
    end;

    procedure TFormAcroLocate.ppShape2DrawCommandCreate(Sender, aDrawCommand:
    TObject);
    var
    lDrawTextCommand: TppDrawText;
    begin
    lSubmitpageNo := ppReport1.AbsolutePageNo;
    lDrawTextCommand := TppDrawText(aDrawCommand);
    lSubmitTopPos := lDrawTextCommand.Top;
    lSubmitLeftPos := lDrawTextCommand.Left;

    end;

    procedure TFormAcroLocate.CreateAcroForm;
    var i : Integer;
    begin
    //GNostice load pdf file;
    //GNostice add input boxes & submit button;
    //Gnostice save modified pdf file;

    //Purely for testing purposes
    for I := 1 to lNoMeters do begin
    showMessage('Input Box: ' + VarToStr(InputArray[i,1]) +
    ' Meter: ' + VarToStr(InputArray[i,2]) +
    ' Page No: ' + VarToStr(InputArray[i,3]) +
    ' Top: ' + VarToStr(InputArray[i,4]) +
    ' Left: ' + VarToStr(InputArray[i,5]));
    end;
    showMessage('Submit: ' +
    ' Page No: ' + IntToStr(lSubmitpageNo) +
    ' Top: ' + IntToStr(lSubmitTopPos) +
    ' Left: ' + IntToStr(lSubmitLeftPos));

    end;
  • edited December 2011
    Hi Tim,

    All published events such as the OnDrawCommandCreate can be created at
    design-time using the Delphi object inspector the same way you would in
    Delphi.

    If you would like to load reports from files, the best solution would be
    to implement the events in RAP so they stay local to the template file
    itself. Otherwise after the report is loaded, you could loop through
    all report components to find the place markers and assign the event
    handlers then.

    http://www.digital-metaphors.com/rbWiki/Delphi_Code/Layouts/Report_Object_Loop

    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • edited December 2011
    Nico

    I never cease to be amazed by my stupidity and ignorance! As i could not
    "see" the objects visually i was blinded to the Object Inspector's drop down
    list of objects. Its all obvious when you know how.

    If i go down the file route and RAP what is the best way to feed the various
    place markers back to the Delphi application. I am struggling to see how i
    do that. Am i being stupid again? I think that i am going to avoid the
    looping through all place markers option.

    Thanks for your patience.

    Merry Christmas to all of you.

    Tim








  • edited January 2012
    Hi Tim,

    If you are not going to loop through each component, you could possibly
    use Report Parameters to access information from the report. See the
    following example on the use of parameters.

    http://www.digital-metaphors.com/rbWiki/End-User/Fundamentals/Report_Parameter_Fundamentals


    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • edited January 2012
    Nico

    As suggested i have looked to use Report Parameters to access information
    from the report but am having problems. I created 4 Parameters called
    MeterNo, PageNo, TopPosition, LeftPosition thinking i could assign and
    iterate through a property list to set and extract the values i require to
    store as my Shape is drawn.


    My first thought was to use the LookupList to store the various values and i
    tried the following:

    procedure Shape1OnDrawCommandCreate(aDrawCommand: TObject);
    begin
    Report.Parameters['MeterNo'].LookupList.Add(DBPipeline1['MeterNo']);
    Report.Parameters['TopPosition'].LookupList.Add(Shape1.Top);
    Report.Parameters['LeftPosition'].LookupList.Add(Shape1.Left);
    Report.Parameters['PageNo'].LookupList.Add(Report.AbsolutePageNo);
    end;

    but i got a Compile Error. LookupList is not listed in the Help file as a
    Rap property.




    I then thought i would try using the Values property as follows:

    procedure Shape1OnDrawCommandCreate(aDrawCommand: TObject);
    var i : Integer;
    begin
    i := DBCalc1.Value;
    Report.Parameters['MeterNo'].values[i] := DBPipeline1['MeterNo'];
    Report.Parameters['TopPosition'].values[i] := Shape1.Top;
    Report.Parameters['LeftPosition'].values[i] := Shape1.Left;
    Report.Parameters['PageNo'].values[i] := Report.AbsolutePageNo;
    end;

    but I got a compile error (Expected: '(' or '[', but found 'values'
    instead.). In the Help File i see that Values is Read Only.


    Am i doing something wrong or is what i am trying not possible.

    Regards

    Tim
  • edited January 2012
    Hi Tim,

    I'm very sorry for the delay in this response, this thread lost its
    "new" status in my reader for some reason.

    Unfortunately the LookupList and Values properties of the Parameters are
    not currently available in RAP. You will either need to create a
    pass-thru function to access them or using a single value for a single
    parameter. We will research adding this capability for a later version
    of ReportBuilder.

    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
This discussion has been closed.