How to: Extend or Replace the Report Builder
Although Visual FoxPro ships with a default Report Builder application, complete with a framework of Report Designer event handlers, you may choose to replace or augment this application with your own implementation.
See Understanding Report Builder Events for more information on how to write a program that complies with the report builder API.
Using an alternate builder application by default
To set the default report builder application
Add a line to CONFIG.FPW that sets the _REPORTBUILDER system variable:
_REPORTBUILDER = mybuilder.prg
Replacing reportbuilder.app "on the fly"
To change report builders in code
Use code like this to switch to an alternate report builder application:
cOriginalBuilderApp = _REPORTBUILDER
_REPORTBUILDER = "mybuilder.prg"
To restore the default:
_REPORTBUILDER = m.cOriginalBuilderApp
Calling back to ReportBuilder.App
To call back to Reportbuilder.app
Use code like this to switch to an alternate report builder application:
parameters returnFlags, eventType, cmdClauses, sessionID
:
do (HOME(1)+"ReportBuilder.App") with returnFlags, eventType,
cmdClauses, sessionID
See the example below for a builder application that calls back to Reportbuilder.app to augment the default behavior.
Example
This example program wraps ReportBuilder.App to provide custom behavior for the CREATE REPORT - Quick Report Command.
The functionality includes:
Adding a "Company letterhead" to the layout.
Updating the header and footer controls.
To use, set _REPORTBUILDER = FULLPATH("quickreportbuilder.prg")
.
*-----------------------------
* QUICKREPORTBUILDER.PRG
*-----------------------------
#DEFINE QUERY_TITLE_LOC "Creating a Quick Report"
#DEFINE HEADER_QUERY_LOC "Company-standard name will be included. "+ ;
"Would you like to add something?"
#DEFINE FINISH_QUERY_LOC "Finished! "+CHR(13)+ ;
"Would you like to adjust the contents?"
#DEFINE COMPANY_HEADER_LOC "ABC Company"
* Return value flags:---------
#DEFINE EVENT_PASSED_TO_VFP 0
#DEFINE EVENT_HANDLED_BY_BUILDER 1
#DEFINE FRX_DISCARD_CHANGES 0
#DEFINE FRX_RELOAD_CHANGES 2
* Hook event types:-----------
#DEFINE EVENTTYPE_REPORTOPEN 7
#DEFINE EVENTTYPE_OBJECTCREATE 2
#DEFINE EVENTTYPE_REPORTSAVE 6
#DEFINE EVENTTYPE_REPORTCLOSE 8
#DEFINE EVENTTYPE_PROPERTIES 1
* ReportBuilder.App Handle Modes:
#DEFINE MODE_HANDLE_CLASS 1
#DEFINE MODE_FORCE_DEBUG 2
#DEFINE MODE_FORCE_NATIVE 3
* standard FRX stuff
#DEFINE OBJTYPE_TEXT 5
#DEFINE OBJTYPE_FIELD 8
#DEFINE OBJTYPE_FONTRES 23
* ----------------------------
#DEFINE MB_YESNO 4
#DEFINE MB_ICONQUESTION 32
#DEFINE IDYES 6
#DEFINE IDNO 7
* ----------------------------
LPARAMETERS returnFlags, eventType, commandClauses, designerSessionId
* This builder only takes action on a quick report.
* Criteria: - Must be a REPORT and not a LABEL layout
* - Must be a CREATE REPORT FROM... command
LOCAL BuilderModule
BuilderModule = HOME()+"ReportBuilder.App"
IF commandClauses.IsReport AND NOT EMPTY(commandClauses.FROM)
LOCAL oFrxHelper
oFrxHelper = NEWOBJECT("frxCursor", HOME()+"FFC\_frxcursor.vcx")
DO CASE
CASE m.eventType = EVENTTYPE_REPORTOPEN
* This is the first event in a quick report.
* First, replace default font resource and font
* info in header to match our requirements, because
* there are some hardcoded metrics for heights in this
* simple example.
* The FRX cursor is in the current workarea:
REPLACE frx.fontface WITH "Courier New" ;
FOR RECNO() = 1 OR frx.objtype = OBJTYPE_FONTRES
LOCATE FOR frx.objtype = OBJTYPE_FONTRES
* Now, add a font resource record for our
* "designed" expression:
SCATTER MEMVAR MEMO
m.penred = 255
m.fontface = "Tahoma"
m.fontstyle = 1
INSERT INTO frx FROM MEMVAR
* Now, reuse the memvars, changing their values, to set up
* the designed expression's record:
m.uniqueid = SYS(2015)
m.objtype = OBJTYPE_TEXT
m.objcode = 0
m.timestamp = oFrxHelper.getFrxTimeStamp()
m.vpos = 20
m.hpos = 20
m.height = 3000
m.width = 50000
m.fillchar = "C"
m.penred = 255
STORE -1 TO m.fillred, m.fillgreen, m.fillblue
m.mode = 1
m.stretch = .T.
m.top = .T.
m.spacing = 2
m.offset = 2
m.resettotal = 1
m.supalways = .T.
m.suprpcol = 3
m.supgroup = 0
m.totaltype = 0
m.expr = INPUTBOX(HEADER_QUERY_LOC, ;
QUERY_TITLE_LOC, ;
COMPANY_HEADER_LOC)
DO CASE
CASE EMPTY(m.expr)
m.expr = COMPANY_HEADER_LOC
CASE ATC(COMPANY_HEADER_LOC,m.expr) = 0
m.expr = COMPANY_HEADER_LOC + " " + ALLTR(m.expr)
ENDCASE
m.expr = ["]+m.expr+["]
INSERT INTO frx FROM MEMVAR
* Finally, tell the Designer to consume our edit:
returnFlags = FRX_RELOAD_CHANGES
CASE m.eventType = EVENTTYPE_REPORTSAVE
* This is the last event in a quick report.
IF NOT EMPTY(m.BuilderModule) AND ;
MESSAGEBOX(FINISH_QUERY_LOC,;
MB_YESNO +MB_ICONQUESTION,;
QUERY_TITLE_LOC) = IDYES
* Give the user a chance to adjust or eliminate
* objects of certain types:
SCAN ALL FOR INLIST(frx.objtype, ;
OBJTYPE_FIELD, OBJTYPE_TEXT)
* Mark the object as "selected" so that the
* builder will act on it:
REPLACE frx.curpos WITH .T.
* Call the builder application, ;
* faking a regular Report Designer event:
do (BuilderModule) with ;
-1, EVENTTYPE_PROPERTIES, ;
m.commandClauses, ;
m.designerSessionId
REPLACE frx.curpos WITH .F.
ENDSCAN
m.returnFlags = FRX_RELOAD_CHANGES
ENDIF
* Find the DATE() expression control created by the
* Quick Report process and convert it into a DATETIME():
LOCATE FOR frx.objtype = OBJTYPE_FIELD AND ;
UPPER(ALLTRIM(frx.expr)) == "DATE()"
LOCAL liWidth
liWidth = oFrxHelper.GetFruTextWidth( ;
TRANSFORM(DATETIME()),;
frx.fontface, frx.fontsize )
REPLACE frx.expr WITH "DATETIME()", ;
frx.width WITH m.liWidth
* Find the _pageno controls and spiff them up a bit:
LOCATE FOR frx.objtype = OBJTYPE_TEXT ;
AND ATC(["PAGE],frx.expr) > 0
IF FOUND()
REPLACE frx.expr WITH ["Page "+TRANSFORM(_PAGENO)],;
frx.objtype WITH OBJTYPE_FIELD, ;
frx.hpos WITH (frx.hpos - (frx.width*2)), ;
frx.width WITH frx.width*3
SKIP
* Remove the other _pageno object that
* follows the "Page" one in a normal quick report:
DELETE
ENDIF
* We need to instruct the Designer to respect our changes:
returnFlags = FRX_RELOAD_CHANGES
OTHERWISE
returnFlags = EVENT_PASSED_TO_VFP
ENDCASE
ELSE
* Parameters are passed by reference:
do (BuilderModule) with m.returnFlags, ;
m.eventType, ;
m.commandClauses, ;
m.designerSessionId
ENDIF
RETURN
See Also
Tasks
How to: Add Your Own Handler to the Report Builder's Registry
Reference
Report Builder Event Handler Registry Table
Concepts
Understanding Report Builder Events