Extending the Visual FoxPro 9 Reporting System
Among the new and improved features in Microsoft Visual FoxPro 9, you'll find the ability to extend the behavior of the reporting system when running reports. In this article, you'll learn about Visual FoxPro 9's report listener concept, how it receives events as a report runs, and how you can create your own listeners to provide different types of output in addition to print and preview.
There are incredible improvements in the Visual FoxPro 9 reporting system. Of several aspects, I'll discuss just one in this article: the ability to extend the behavior of the runtime reporting engine.
The reporting engine in Visual FoxPro 9 splits responsibility for reporting between the report engine, which now just deals with data handling and object positioning, and a new object known as a report listener, which handles rendering and output.
The Visual FoxPro development team had several goals in mind when they worked on the runtime improvements, including:
- Handling more types of report output than just printing and previewing
- Using GDI+ for report output. This provides many significant improvements, such as more accurate rendering, smooth scaling up and down of images and fonts, and additional capabilities, such as text rotation.
- Providing a more flexible and extendible reporting system
You have access to both the old report engine and the new one, so you can run reports under either engine as you see fit. But once you see the benefits of the new report engine, you won't want to go back to old-style reporting.
Reporting System Architecture
Before Visual FoxPro 9, the report engine was monolithic; it handled everything and with a few exceptions (user-defined function, expressions for OnEntry and OnExit of bands, and so forth), you couldn't interact with it during a report run.
The new reporting engine splits responsibility for reporting between the report engine, which now deals only with data handling and object positioning, and a new object known as a report listener, which handles rendering and output. Because report listeners are classes, we can now interact with the reporting process in ways we could only dream of before.
Report listeners produce output in two ways. Page-at-a-time mode renders a page and outputs it, then renders and outputs the next page, and so on. This mode is used when a report is printed. In all-pages-at-once mode, the report listener renders all the pages and caches them in memory. It then outputs these rendered pages on demand. This mode is used when a report is previewed.
New Reporting Syntax
Visual FoxPro 9 supports running reports using the old report engine; you use the REPORT command just as you did before (although, as you'll see in a moment, you can use a new command to override the behavior of REPORT). To get new-style reporting behavior, use the new OBJECT clause of the REPORT command. The OBJECT clause supports two ways of using it: by specifying a report listener and by specifying a report type. Microsoft refers to this as object-assisted reporting.
A report listener is an object that provides new-style reporting behavior. Report listeners are based on a new base class in Visual FoxPro 9 called ReportListener. To tell Visual FoxPro 9 to use a specific listener for a report, instantiate the listener class and then specify the object's name in the OBJECT clause of the REPORT command. Here's an example:loListener = createobject('MyReportListener')
report form MyReport object loListener
If you'd rather not instantiate a listener manually, you can have Visual FoxPro do it for you automatically by specifying a report type:report form MyReport object type 1
The defined types are 0 for outputting to a printer, 1 for previewing, 2 for page-at-a-time mode but not to send the output to a printer, 3 for all-pages-at-once mode but not invoke the preview window, 4 for XML output, and 5 for HTML output. Other, user-defined, types can also be used.
When you run a report this way, the application specified in the new _REPORTOUTPUT system variable (ReportOutput.APP in the Visual FoxPro home directory by default) is called to determine which listener class to instantiate for the specified type. It does this by looking for the listener type in a listener registry table built into the APP (although you can also tell it to use an external table). If it finds the desired class, it instantiates the class and gives a reference to the listener object to the reporting engine. Thus, using OBJECT TYPE SomeType in the REPORT command is essentially the same as:loListener = .NULL.
do (_ReportOutput) with SomeType, loListener
report form MyReport object loListener
By: Doug Hennig
Doug Hennig is the author of the award-winning Stonefield Database Toolkit (SDT), the award-winning Stonefield Query, the MemberData Editor, Anchor Editor, and CursorAdapter and DataEnvironment builders that come with Microsoft Visual FoxPro, and the My namespace and Upsizing Wizard in Sedna. Doug is co-author of the What’s New in Visual FoxPro series (the latest being What’s New in Nine) and The Hacker’s Guide to Visual FoxPro 7.0, available from Hentzenwerke Publishing (http://www.hentzenwerke.com).
Doug has spoken at every Microsoft FoxPro Developers Conference (DevCon) since 1997 and at user groups and developer conferences all over the world. He is one of the administrators for the VFPX community extensions Web site (http://www.codeplex.com/Wiki/View/aspx?ProjectName=VFPX).
Doug has been a Microsoft Most Valuable Professional (MVP) since 1996 and was named the 2006 winner of the FoxPro Community Lifetime Achievement Award. His Web sites are http://www.stonefield.com and http://www.stonefieldquery.com, and his blog is at http://doughennig.blogspot.com.
The Visual FoxPro 9 reporting system raises events in a new base class, called ReportListener. ReportListener is the key to the different types of provided report output, also giving us the ability to change how a report is rendered.