Drawing custom objects with XFRX#DRAW

The XFRX#DRAW class described in the previous chapter is also able to modify the content of XFF files: to add custom graphics, text, new pages, hyperlinks and bookmarks, both during the report generation process as well as after the report is generated.


Drawing custom objects to existing XFF files

To add custom graphics objects to XFF files, instantiate the XFRX#DRAW object as described in previous chapter and use the properties and methods described in chapter 17.3 XFRX#DRAW functions below. All changes are immediately written to the XFF file and once the XFRX#DRAW class reference is released, the changes are written to the disk (or other media the XFF file is stored on).

Drawing custom objects during report generation process

Alternatively, you can create scripts, which can be invoked on the fly, during the report generation process. These scripts can either be implemented as methods of a class, or, for rectangle-bound scripts, can be entered into a comment field of a rectangle object on the report.

In XFRX for VFP 9.0, the XFF file is always internally used when a report is processed. However, in XFRX for VFP 8.0, you can generate the target documents “directly”, in which case, however, the XFF scripts would not be evaluated.

Page-bound scripts

The page-bound scripts are implemented as methods of an arbitrary class – you can use a custom class that is instantiated before XFRX is executed, implement the scripts as methods of the current form or whatever else is convenient in your application environment. Each script method accepts one parameter: the XFRX#DRAW object reference. This reference links to the document that is being generated.

Example:

DEFINE CLASS myXFRXScripts AS CUSTOM
 
   PROCEDURE drawBlueRectangle
      LPARAMETERS m.oXFD
      m.oXFD.setColor(0,0,255,-1,-1,-1)
      m.oXFD.drawRectangle(100,200,50,50)
   ENDPROC
 
ENDDEFINE

Before XFRX is called, the scripts are registered with RegisterScript() in the XFRX session class instance so that XFRX new about these scripts and invoked them as required. You can execute the scripts on each page, odd or even pages or arbitrary pages. Please see RegisterScript chapter for detail description of this method and its parameters.

Example:

*
*Draw blue rectangle on each page
*
m.loScripts = createobject("myXFRXScripts")
m.loXFRXSession.registerScript(loScripts,"drawBlueRectangle",0,"ALL",0)

Rectangle-bound scripts

The rectangle-bound scripts are bound to a specific rectangle on the report and are executed instead of drawing this rectangle to the output.

There are two ways how the scripts can be implemented: named scripts, which are implemented as a method of a class, or scripts written directly to the comment field of the rectangle in the report definition.

Named scripts

If the script is implemented as a method of a class, it needs to be registered similarly as page-bound scripts, but only the first two parameters are required – the object reference and the script name:

m.loScripts = createobject("myXFRXScripts")
m.loXFRXSession.registerScript(loScripts,"drawBlueRectangle")

To link the script with a rectangle, add “#UR SCRIPT NAME <script name>” (without the quotation marks) as a comment of the rectangle.

Scripts written in the rectangle comment field

Alternatively, the script can be entered into the comment field of the rectangle. This technique is available for VFP 8.0 and higher, but its usage is limited for VFP 8.0 because the comment field is small and only a limited amount of text can be entered into it.

The script is entered between #UR SCRIPT BEGIN and #UR SCRIPT END lines.

These scripts are neither named not registered. The content between these lines is supposed to accept the XFRX#DRAW object reference parameter and is evaluated via EXECSCRIPT( ) function.

Example:

When inside of the rectangle-bound script, the coordinates origin is shifted: 0,0 represents the upper left hand corner of the rectangle.

The position and size of the bounding rectangle can be retrieved with GetBoundingRectangle() method.

Converting rectangle-bound objects to pictures

The content of the rectangle-bound scripts can be alternatively rendered as a picture, which is then placed to the output. To do this, add PICTURE clause to the #UR SCRIPT BEGIN or #UR SCRIPT NAME <script name> line in the comment field.

The PICTURE can optionally be followed by a DPI value, representing the DPI (dots per inch) of the picture created. The default DPI is 96, which is suitable for previewing on screen, but you may want to increase the DPI value to increase the picture quality.

You can also specify the picture type by adding TYPE clause followed by one of the following values: BMP, JPEG (JPG), PNG, TIFF (TIF) and EMF. The default picture type is JPG.

Next keywords are: 
  • BPP - bits per pixel; default value is 24; values are 1,4,8,16,24,32; XFRX 15.5
  • JPEGQ - jepg quality; default value is 96 ; XFRX 15.5
  • TRANSPARENT- transparent background mode for TIFF, PNG and EMF; default is opaque; XFRX 15.5

Sending parameters to named scripts

The named scripts can optionally accept further parameters. The parameters are specified via PARAMETERS clause followed by the parameters, which are evaluated at the time of report processing.

Example:

DEFINE CLASS myXFRXScripts as Custom
   PROCEDURE fancyRectangle
      LPARAM m.oXFD, m.boxwidth, m.boxheight
      *
      * This script draws little boxes around the bounding rectangle.
      * The height and width of the rectangles can be sent as parameters.
      * The default width and height is 5 points. (1 point = 1/72 inch).
      *
      IF EMPTY(m.boxwidth)
         m.boxwidth = 5
      ENDIF
      IF EMPTY(m.boxheight)
         m.boxheight = m.boxwidth
      ENDIF

      m.oXFD.setUnit("pt")
      m.loBox = m.oXFD.getBoundingRectangle()
      m.oXFD.setColor(0,0,0)

      LOCAL m.i
      FOR m.i = 0 TO INT(m.loBox.nwidth/m.BOXWIDTH)-1
          m.oXFD.setColor(0,0,0,INT(RAND()*256),INT(RAND()*256),INT(RAND()*256))
          m.oXFD.drawRectangle(m.i*m.BOXWIDTH, 0, m.BOXWIDTH, m.boxheight,1,1)
          m.oXFD.setColor(0,0,0,INT(RAND()*256),INT(RAND()*256),INT(RAND()*256))
          m.oXFD.drawRectangle(m.i*m.BOXWIDTH, ;
                              INT(m.loBox.nheight/m.boxheight-1)*m.boxheight, m.BOXWIDTH, m.boxheight,1,1)
      ENDFOR

      FOR m.i = 1 TO INT(m.loBox.nHeight/m.boxheight)-2
          m.oXFD.setColor(0,0,0,INT(RAND()*256),INT(RAND()*256),INT(RAND()*256))
          m.oXFD.drawRectangle(0, m.i*m.boxheight, m.BOXWIDTH, m.boxheight,1,1)
          m.oXFD.setColor(0,0,0,INT(RAND()*256),INT(RAND()*256),INT(RAND()*256))
          m.oXFD.drawRectangle(int(m.loBox.nwidth/m.BOXWIDTH-1)*m.BOXWIDTH, ;
                               m.i*m.boxheight, m.BOXWIDTH, m.boxheight,1,1)
      ENDFOR
   ENDPROC
ENDDEFINE

XFRX#DRAW functions

This chapter gives a brief list of properties and methods implemented in the XFRX#DRAW class. For detailed description if the properties, methods and their parameters please see the XFRX#DRAW class reference on page 92).

XFF document navigation

Whenever you draw anything to a XFF document, the drawing is always added on top of  the “current page”. The current page is stored in a readonly property CurrentPage nReportPageNo. The total number of pages is stored in PageCount property. To navigate on the pages, use GoTop(), GoBottom() and GoToPage(nPageNo) methods.

Adding pages

AddPage() method creates a new page at the end of the document. You can either specify the size of the new page or use the same size as the current page.

Coordinates units

The default unit is Point (1/72 inch). You can use setUnit(cUnit) method to switch to a different unit. The available units are: centimeters (cm), inches (in), points (pt) and pixels (px).

17.3.4 Drawing functions

Use SetColor() method to set colors for subsequent drawing method calls, the default colors are black for pen and white for background.

Drawing text

Use setFont() method to set the font name, size and attributes. DrawText() draws a text either at a given position, at a position defined by SetPos() method or at end of an output of the previous DrawText() method call – “current position”. After each DrawText() method call, the “current position” advances depending on the height and width of the text. GetXPos() and GetYPos() return the current position. DrawTextBox() draws a text into a given bounding rectangle – word wraps long lines and optionally expands the height of the bounding box to accommodate the whole text.

To maintain backward compatibility with PDF Library, OutText() is a synonym of DrawText().

Drawing basic shapes

drawLine() draws a point to point line, drawRectangle() draws a rectangle, rounded rectangle or an ellipse.

Drawing pictures

DrawPicture() method draws a picture within a given bounding rectangle.

Tooltips, hyperlinks and bookmarks

Each text drawn by DrawText() or DrawTextBox() can have a tooltip, can serve as a target for a bookmark and can be a hyperlink or a target or a hyperlink. Please see tcLinkName, tcLinkRef, tcBookmark and tcTooltip parameters of DrawText() and DrawTextBox() methods in XFRX#DRAW class reference on page 92).