What's New in the Visual FoxPro 9.0 Report Writer 

 

Cathy Pountney
www.frontier2000.com

August 2004

Applies to:
   Visual FoxPro 9.0

Read the companion article, Visual FoxPro 9.0 Report Writer In Action.

Summary: Learn about the new features in the Microsoft Visual FoxPro 9.0 Report Writer, including the new reusable data environments, report protection, and several user interface enhancements. You will also learn about enhancements to layout objects, improvements for international users, several printing enhancements, and enhancements to data groups. In addition, you will learn about two of the best improvements to the Visual FoxPro (VFP) 9.0 Report Writer: multiple-detail bands and extensibility. Finally, you will learn details of the Visual FoxPro report (FRX) structure. (63 printed pages)

Contents

Introduction
Extensibility
Data Environments
Protection
UI Enhancements
Layout Object Enhancements
International Features
Printing Enhancements
Data Group Enhancements
Multiple-Detail Bands
The FRX
Conclusion
Bio

Introduction

Microsoft has significantly improved the VFP 9.0 Report Writer while recognizing the significant investment developers have in existing FRX-based reports. Therefore, the VFP 9.0 Report Writer is compatible with previous versions of VFP reports. The VFP 9.0 Report Writer is a great blend of the old and the new.

Extensibility

Prior to VFP 9.0, the Report Engine handled everything, including processing the data, object positioning, rendering, printing, and previewing. There was no way to "hook" into the Report Engine and customize it, as you can with other areas of VFP. One if the most significant changes to the VFP 9.0 Report Writer is the new extensibility features. The Report Designer, the Report Engine, and the Preview Container have been exposed to the developer.

Report Builder

The VFP 9.0 Report Writer includes a new design-time feature called Builder Hooks. Several events of the Report Designer are exposed and an independent Xbase component, called the Report Builder, can be invoked to handle them. This application can be used to invoke your own dialog boxes, augment the native Report Designer behavior, or override the native behavior.

VFP includes an extensive Report Builder application that includes new features and provides a better user interface for designing reports. The Report Builder is controlled by a new system variable, _REPORTBUILDER. If this variable is empty, the native dialog boxes appear. To activate the builder hooks, set this variable to an appropriate application. For example, to use the Report Builder shipped with VFP 9.0, issue the following command:

_REPORTBUILDER = HOME() + "REPORTBUILDER.APP"

Some portions of this article assume the native dialog boxes are in place and the _REPORTBUILDER system variable is empty. Other places assume the new dialog boxes are in place and the _REPORTBUILDER system variable is set to "REPORTBUILDER.APP." If you are not experiencing the behavior described or are not seeing the dialog boxes described, changing the value of _REPORTBUILDER may solve the problem.

Report Engine

In the new output system (Object-Assisted Output), the Report Engine handles data-centric chores, such as moving through the scope and expression evaluation. However, when it comes time to create output, it defers the work to a new base class, called ReportListener. The new class renders the report contents in a more sophisticated way, using GDI+, and it also gives Xbase users a chance to interact with the output process. Figure 1 shows how the pieces fit together.

Click here for larger image

Figure 1. Use the new ReportListener class to manipulate reports. (Click image for a larger view.)

To use a ReportListener class, use the new clause on the REPORT FORM command as follows:

oListener = CREATEOBJECT("ReportListener")
oListener.ListenerType = 1 && Preview, or 0 for Print
REPORT FORM <name> <clauses> OBJECT oListener

VFP 9.0 also provides a second technique for using a ReportListener class. You may set the value of a new system variable, _REPORTOUTPUT, to the name of an application that can determine which ReportListener class to use based on the type of output you have chosen.

When using Object-Assisted Output, a report is processed using one of two main modes, depending on its ListenerType property value. You can think of these two modes as print-appropriate and preview-appropriate, or page-at-a-time and all-pages-at-once. In the first mode, the Listener triggers an OutputPage event as it prepares each page, just as it sends each page to the printer or print queue.

In the second mode, the Listener prepares all pages for rendering and caches them. When it is finished, you can invoke the OutputPage method to ask for the page output of any and all pages included in output, by page number.

Preview Container

In VFP 9.0, another piece of the extensibility puzzle is the Preview Container. With this hook, you can use the new preview container shipped with VFP 9.0 or write your own preview container. The old native preview container is still available when you are not using the new object-assisted output.

A new system variable, _REPORTPREVIEW, contains the name of the application that determines what preview container to use. By default, this variable points to ReportPreview.app. This new application contains a lot of improvements over the old preview, including: more zoom levels, control of the toolbar, control of the caption, multiple page preview, and better quality using GDI+. Figures 2 and 3 show the differences between the old preview surface and the new preview surface.

Click here for larger image

Figure 2. The output in the older preview container is not very crisp. (Click image for larger view.)

Click here for larger image

Figure 3. The new preview container has much better quality and more sophisticated options. (Click image for larger view.)

Notice the difference in quality between the old and new preview containers. The new container has much crisper fonts than the old one. This can be credited to using GDI+ to output information. Also note the differences in the docked toolbar. The toolbar on the newer style preview has more options, including multiple-page layouts.

Traditional Output

A new command, SET REPORTBEHAVIOR, may be used to turn Object-Assisted Output on or off. The new output rendering engine and the new Preview surface both have some significant differences from the old style of output. Alignment, kerning, and spacing are different between GDI and GDI+, which could significantly change how your existing reports look. Therefore, REPORTBEHAVIOR is set to 80 by default, which turns the Object-Assisted Output off and reports processes as they did prior to VFP 9.0.

If you want to globally turn Object-Assisted Output on, you may change the value of this setting in the Options dialog box (shown in Figure 4), or you may issue the following command:

SET REPORTBEHAVIOR 90

Figure 4. Use the Run-time behavior option on the Options dialog box to change the SET REPORTBEHAVIOR setting.

When REPORTBEHAVIOR is set to 90, REPORT FORM commands automatically behave as though you used the OBJECT clause, without any further changes to your code. VFP uses the _REPORTOUTPUT system variable to determine what application to use for nominating the appropriate ReportListener class for each REPORT FORM command.

With the new extensibility features in the VFP 9.0 Report Writer, you can tap into the Report Builder, the Report Engine, and the Preview surface. You can globally turn on the new features or you can turn them on individually for various reports. You can also leave the new features off and run reports as if you were in prior versions of VFP.

For more information about how to use Object-Assisted Output, see: The VFP 9.0 Report Writer In Action.

Data Environments

The VFP 9.0 Report Writer can now share Data Environments with other reports. Data Environments can also be saved as a class and then loaded into reports as needed. This offers a great reuse scenario for defining common reporting needs.

Save As Class

To save a Data Environment as a class, start by defining the Data Environment in a report as usual. While the Data Environment window is still active, select the new Save As Class... option from the File menu (see Figure 5).

Figure 5. A new "Save As Class..." option appears on the File menu when the Data Environment is the active window.

After selecting the Save As Class... option, the Save As Class dialog box appears as shown in Figure 6. The DataEnvironment button of the Save option group is the only option button enabled when saving a Data Environment of a report.

Figure 6. Use the Save As Class dialog box to declare the name of the new class and the class library for saving the Data Environment of a report.

Enter a name for the class in the Name text box. Next, enter the name of the class library you want the new class saved in. If you enter the name of a class library that does not exist, the new class library is created for you. You can also use the Ellipse (...) button to locate an existing class library. Finally, you may optionally enter a description of the new class.

Loading a DE

In addition to manually defining the Data Environment for a new report, VFP 9.0 also gives you the option to load the Data Environment from an existing report or from a saved DataEnvironment class. The Load Data Environment... option on the Report menu (see Figure 7) allows you to select which Data Environment to load.

Figure 7. Use the Load Data Environment... option to load a Data Environment from an existing report or from a DataEnvironment class.

Note   The Load Data Environment feature is only available through the new ReportBuilder dialog boxes. You must issue _REPORTBUILDER = HOME() + "ReportBuilder.app" to take advantage of this feature.

From a Report

When loading the Data Environment from another report, all the code and members of the original Data Environment are copied into the new report. This means any changes made to the original report's Data Environment after the fact are not propagated into reports created from the original report.

The Report Properties dialog box, as shown in Figure 8, appears after selecting Load Data Environment... from the Report menu. Use this menu to select the report whose Data Environment you wish to copy into this report.

Figure 8. Use the Data Environment tab of the Report Properties dialog box to choose which report you want to copy a Data Environment from.

Select the Copy from another report file option button and then click the Select... button. This invokes the Open dialog box so you can choose which report to copy from. Once you chose a report, a confirmation dialog box appears (see Figure 9).

Figure 9. Confirm your intentions to copy a Data Environment using this dialog box.

VFP 9.0 is about to copy the Data Environment from another report to the current report. Therefore, VFP 9.0 notifies you that it is about to overwrite the current Data Environment, and you must click Yes to continue. This helps remind you that anything you have defined in the Data Environment of the current report is about to be overwritten. If you click No, changes are not made and the process is aborted. When you click Yes, the Data Environment is copied and you are notified with the dialog box shown in Figure 10.

Figure 10. This dialog box confirms the Data Environment has been successfully copied into the current report.

You are now done copying the Data Environment. You may manipulate the Data Environment as needed. However, remember that any changes made to the original report's Data Environment after this point, are not propagated to this report.

From a DE Class

When loading the Data Environment from a class, code is added to the Data Environment of the new report to bind to the original DataEnvironment class and instantiate it at run time. This means future changes made to the DataEnvironment class will propagate into any reports using the DataEnvironment class.

Using the Report Properties dialog box, shown in Figure 8, click the Link to a visual DE class button. Next, click the Select... button to invoke the Open dialog box that you can use to choose which class library and which class to use. The same confirmation dialog box shown in Figure 9 appears after selecting a class. After confirming your intentions, the Data Environment is updated and you are notified of its completion with the dialog box shown in Figure 10.

At this point, code has been added to some of the Data Environment methods. Some of the methods have very simplistic code with nothing more than a DODEFAULT() command. The reason for this is BindEvents() does not function unless the method contains at least one line of code.

Data Environment Code

Loading a Data Environment from a class automatically adds code to several methods as shown and described below.

Init Method

The following code in the Init method is needed to ensure BindEvents() works as expected.

*-----------------------------------------------------*
* THIS METHOD CODE WAS INSERTED BY THE REPORT BUILDER *
*-----------------------------------------------------*
    DODEFAULT()

BeforeOpenTables Method

The following code creates a new property on the Data Environment that holds an object reference to the DataEnvironment class being loaded. Next, events in this Data Environment are bound to the corresponding events in the DataEnvironment class. However, the Init and Destroy events are not bound. Finally, the BeforeOpenTables event of the DataEnvironment class is fired.

*-----------------------------------------------------*
* THIS METHOD CODE WAS INSERTED BY THE REPORT BUILDER *
*-----------------------------------------------------*
    LOCAL loMember, laDEEvents[1], liMember, liMembers, loBoundMember
    THIS.AddProperty( "BoundDE", NEWOBJECT( "de_insurance", "c:\vfp9\rwde.vcx" ))
    IF VARTYPE( THIS.BoundDE ) = "O" AND UPPER( THIS.BoundDE.BaseClass ) = "DATAENVIRONMENT"
        * Bind events here, skipping the Init and Destroy.
        * The FRX DE and its members can only have base events,
        * so not that much PEMSTATUS checking is necessary:
        liMembers = AMEMBERS( laDEEvents, THIS, 3 )       
        FOR liMember = 1 TO liMembers
            IF INLIST( UPPER( laDEEvents[ liMember, 1] ), "INIT", "DESTROY" )
                LOOP
            ENDIF
            IF INLIST( UPPER( laDEEvents[ liMember, 2] ), "EVENT", "METHOD" )
                BINDEVENT( THIS, ;
                           laDEEvents[ liMember, 1], ;
                           THIS.BoundDE, ;
                           laDEEvents[ liMember, 1] )
            ENDIF
        ENDFOR
        * Now do the members with appropriate checking,
        * again skipping the Init and Destroy:
        FOR EACH loMember IN THIS.Objects
            IF PEMSTATUS( THIS.BoundDE, loMember.Name, 5 ) AND ;
                UPPER( PEMSTATUS( THIS.BoundDE, loMember.Name, 3 ) = "OBJECT"
                loBoundMember = EVAL( "THIS.BoundDE." + loMember.Name )
                IF ( loBoundMember.BaseClass == loMember.BaseClass )
                    liMembers = AMEMBERS( laDEEvents, loMember, 3 )
                    FOR liMember = 1 to liMembers
                        IF INLIST( UPPER( laDEEvents[ liMember, 1] ), "INIT", "DESTROY" )
                            LOOP
                        ENDIF
                        IF INLIST( UPPER( laDEEvents[ liMember, 2] ), "EVENT", "METHOD" )
                            BINDEVENT( THIS, ;
                                       laDEEvents[ liMember, 1], ;
                                       loBoundMember, ;
                                       laDEEvents[ liMember, 1] )
                        ENDIF
                    ENDFOR
                ENDIF
            ENDIF            
        ENDFOR
        THIS.BoundDE.BeforeOpenTables()
    ENDIF

AfterCloseTables Method

The following code in the AfterCloseTables method is needed to ensure BindEvents() works as expected.

*-----------------------------------------------------*
* THIS METHOD CODE WAS INSERTED BY THE REPORT BUILDER *
*-----------------------------------------------------*
    DODEFAULT()

Destroy Method

The following code added to the Destroy method unbinds methods from this report's Data Environment from the DataEnvironment class. The code also removes the object reference to the DataEnvironment class.

*-----------------------------------------------------*
* THIS METHOD CODE WAS INSERTED BY THE REPORT BUILDER *
*-----------------------------------------------------*
    LOCAL loMember
    UNBIND( THIS )
    FOR EACH loMember in THIS.Objects
        UNBIND( loMember )
    ENDFOR
    IF PEMSTATUS( THIS, "BoundDE", 5 ) AND UPPER( PEMSTATUS( THIS, "BoundDE", 3 )) = "PROPERTY"
        THIS.BoundDE = NULL
    ENDIF

Error Method

The following code in the Error method is needed to ensure BindEvents() works as expected.

*-----------------------------------------------------*
* THIS METHOD CODE WAS INSERTED BY THE REPORT BUILDER *
*-----------------------------------------------------*
    LPARAMETERS nError, cMethod, nLine
    DODEFAULT( nError, cMethod, nLine )

Protection

In VFP 9.0, you can create protection for one or more layout objects when using the Report Designer or Label Designer. This gives you the ability to let your user modify a report, yet keep them from making certain changes.

Setting Protection Flags

Layout objects have five different protection modes you can set, with Field objects having an additional protection option. Bands have two different protection modes you can set. The report itself has a variety of different protection modes you can set.

Note   The new protection features can only be set through the new ReportBuilder dialog boxes. You must issue _REPORTBUILDER = HOME() + "ReportBuilder.app" to take advantage of these features.

Protecting an Object

To protect a layout object in the Report Designer, select the Properties dialog box for the object. The Properties dialog box can be invoked from the Report menu after selecting the object, from the context menu of the object, or by double-clicking the object. Figure 11 shows the Protection tab of the Properties dialog box for a field object.

Figure 11. Use the Protection tab of the Properties dialog box to set protection modes of a layout object.

You can set the following five protection modes for layout objects:

  • Place a check mark in the selection box for Object cannot be moved or resized to prevent the user from moving this layout object to a different position on the design surface and to prevent the user from resizing this object.
  • Place a check mark in the selection box for Object cannot be edited to prevent the user from making any changes to the properties of this layout object.
  • Place a check mark in the selection box for Object cannot be deleted to prevent the user from deleting this object.
  • Place a check mark in the selection box for Object cannot be selected to prevent the user from selecting this object. When this option is selected, the protection behaviors of Object cannot be moved or sized, Object cannot be edited, and Object cannot be deleted are also imposed.
  • Place a check mark in the selection box for Object is not visible in Designer to prevent this object from appearing in the Report Designer in protected mode. When this option is selected, the protection behavior of the other four options is also imposed.

The Design-time caption portion of this dialog box only applies to Field objects. The literal string entered into this text box is displayed in the Report Designer, instead of the Expression. This gives you the opportunity to display something that is user-friendly instead of a complicated expression.

Protecting a Band

To protect a band in the Report Designer, select the Properties dialog box for the band. The Properties dialog box can be invoked from the Edit Bands... option on the Report menu, from the context menu of the band, or by double-clicking the gray bar of the band. Figure 12 shows the Protection tab of the Properties dialog box for a band.

Figure 12. Use the Protection tab of the Band Properties dialog box to set protection modes of the band.

You can set the following two protection modes for bands:

  • Place a check mark in the selection box for Band cannot be edited to prevent the Band Properties dialog box from being accessible to the user.
  • Place a check mark in the selection box for Band cannot be resized to prevent the user from resizing the band.

Protecting a Report

To set overall report protection, select the Report Properties dialog box. You can invoke this dialog box by selecting Properties from the Report menu or from the context menu of the report. Figure 13 shows the Protection tab of the Report Properties dialog box.

Figure 13. Use the Protection tab of the Report Properties dialog box to set overall protection modes of a report.

The top portion of this dialog box allows you to define which tabs of the Report Properties dialog box are unavailable to the user. For each of the selections made in this area, the applicable tab of the Report Properties dialog box is disabled. The Protection option is always checked and disabled. The Ruler/Grid option is disabled because the tab cannot be protected; however, it appears on the dialog box so that the selections are consistent with the tabs on the Report dialog box.

The bottom portion of this dialog box allows you to define what menu options are unavailable to the user. For each of the selections in this area, the applicable menu option is disabled.

Honoring Protection Flags

To invoke protection during a Report Designer or Label Designer session, use the PROTECTED keyword as shown in the following examples:

CREATE REPORT MyReport PROTECTED
MODIFY REPORT MyReport PROTECTED
CREATE LABEL MyLabel PROTECTED
MODIFY LABEL MyLabel PROTECTED

If the PROTECTED keyword is not used, the Report Designer functions as if no protection was applied to the layout objects.

UI Enhancements

Many changes have been made to the user interface to make designing reports easier and more intuitive. Menus have been overhauled, context menus have been changed, and new options have been added to the Report Designer toolbar. The Expression Builder dialog box and Expression Builder Options dialog box have new behaviors, and a few other miscellaneous user interface enhancements have been added to the VFP 9.0 Report Writer.

Menus

The report menu system has been overhauled in VFP 9.0 to accommodate new options. In addition, some options have been relabeled for clarity and some options have been repeated on several menus to allow easier access. Figures 14-16 show the new menu changes.

Figure 14. The new "Save As Class..." option appears on the File menu.

Figure 15. A new option has been added for the Report Designer toolbar and horizontal lines have been added to separate the Grid Lines and Show Position options from the other options.

Figure 16. Many changes appear on the Report menu, including relabeled options, new options, and the addition of the Print Preview option.

Context Menus

Existing context menus have been improved with additional items and are more consistent with the dialog boxes they invoke. Other items in the Report Designer that previously did not have context menus now do. Figures 17-19 show the new changes.

Figure 17. The global context menu has new options and one relabeled option.

Figure 18. Invoke the new band context menu by right-clicking the gray bar of any band.

Figure 19. Invoke the layout object context menu by right-clicking any layout object.

Toolbar

The Report Designer toolbar has some new buttons, as shown in Figure 20.

Figure 20. New options for Page Setup and Font Properties have been added to the Report Designer toolbar.

Expression Builder Dialog Box

A few changes have been made to the Report Expression dialog box. Figure 21 shows the expanded Report Expression dialog box, which allows more room for entering a report expression.

Figure 21. Take advantage of the taller "Expression for Field on Report:" edit box when entering wordy expressions.

When the _REPORTBUILDER system variable is empty the native behavior of the Expression Builder dialog box is as follows. Only tables defined in the Data Environment are listed in the Fields list box. Tables opened outside of the Data Environment are not available in the list box.

When the _REPORTBUILDER system variable is set to ReportBuilder.app, the behavior of the Expression Builder dialog box is quite different. First of all, the Expression Builder defined in _GETEXPR is invoked instead of the native Expression Builder. Figure 22 shows the default Expression Builder dialog box.

Figure 22. Use the "From table" combo box to select fields from any open table.

This Expression Builder dialog box has a combo box for choosing which table should be used when listing fields in the Fields list box. However, only tables that are currently in use are listed in the combo box. This is an important point to remember because tables defined in the Data Environment are not automatically opened by the Report Designer; therefore, they do not automatically appear in the combo box.

This gives you the ability to control what tables are available to end-users when you allow them to modify reports within your application. You may have defined some tables in the Data Environment that you need, but you do not want the user to have access to. So because you have to specifically open the tables you want the users to access, you can omit any tables you want to keep them from.

Expression Builder Options Dialog Box

The Field aliases option group is now enabled in the Expression Builder Options dialog box, as shown in Figure 23. This option group allows you to indicate whether or not you want the table alias added to the report expression when picking fields from the Expression Builder dialog box.

Figure 23. Use the Field aliases option group to indicate whether or not field aliases are added to fields selected from the Expression Builder dialog box.

The Always add alias and Never add alias option buttons cause VFP 9.0 to automatically add the table alias, or not add the table alias, for all fields. The behavior of the Add non-selected alias only option button depends on the value of the _REPORTBUILDER system variable. If the _REPORTBUILDER system variable is empty, any field chosen from a table that is not the InitialSelectedAlias is prefixed with the table alias. Fields from the InitialSelectedAlias table are not prefixed with the table alias.

If the _REPORTBUILDER system variable is set to ReportBuilder.app, the Add non-selected alias only option uses slightly different logic. The currently selected alias is used instead of the InitialSelectedAlias for determining whether or not to prefix the field with the table alias.

In addition to selecting a field from the Expression Builder dialog box, dragging a field from the Data Environment to the Report Designer surface honors the setting of the Field aliases option group. Also, a new option exists on the Report tab of the Options dialog box, as shown in Figure 24. This option determines what the default Field aliases setting is for all newly created reports.

Figure 24. Use the Expression Builder option on the Reports tab of the Options dialog box to set the default behavior for the Expression Builder.

Miscellaneous UI Enhancements

Several other enhancements to the user interface have improved the report designing experience.

Mouse cursor

The mouse cursor now changes to provide a visual cue when an object can be resized (see Figure 25).

Figure 25. Use the new mouse cursor to know when an object can be resized.

Multiple Selection dialog box

VFP 9.0 now has a Multiple Selection dialog box, which allows you to set Protection and Print when properties of more than one layout object at once. It also allows you to change any of the other properties of any individual layout object. To use this new feature, select more than one layout object, and then double-click any one of the objects to invoke the Multiple Selection dialog box, shown in Figure 26.

Figure 26. Use the Selection tab of the Multiple Selection dialog box to choose which layout objects you want to work on.

The layout objects that were selected when this dialog box was invoked are listed in the first tab of this dialog box. To work with all layout objects defined in a report, use CTRL+A to select all layout objects before invoking this dialog box.

The Sort by option allows you to sort the list of layout objects by Type or Location within the report. The Remove from list button removes the selected layout objects from the list. Double-click any item in the list, and the applicable Properties dialog box for the individual object is invoked. The Properties tab of the Multiple Selection dialog box, shown in Figure 27, is used to change the properties of all the items listed in the Selection tab.

Figure 27. Use the Properties tab of the Multiple Selection dialog box to change the Protection properties and the Print when logic of the selected layout objects all at once.

Select the Apply these protection settings to the selected objects check box to enable the Protection options. Select the Apply this condition to the selected objects upon saving check box to enable the Print when option. Change the Protection and Print when settings as needed, and then select OK to close the dialog box and apply the changes to all the layout objects listed on the first tab.

More Zoom Levels

The Preview window has more Zoom levels (see Figure 28).

Figure 28. Use any of the new zoom levels in the VFP 9.0 preview for better visibility.

VFP 9.0 has made a lot of improvements to the user interface, including menus, context menus, and toolbars. The changes to the Expression Builder dialog box and the Expression Builder Options dialog box have also increased the options available to you. Other improvements include the mouse cursor, the Multiple Selection dialog box, and more Zoom levels.

Layout Object Enhancements

A few improvements have been added for layout objects, including an option to control template characters, a trim mode for character expressions, and relative and absolute positioning.

Note   To take advantage of the Trim Mode enhancement, you must be using the new Object Assisted Output, either directly by creating a ReportListener object, or indirectly by using the SET REPORTBEHAVIOR 90 command.

Template Characters

The Field Properties dialog box has a new section for Template characters, as shown in Figure 29. The two available options are Overlay and Interleave. These determine how special characters are used in the format.

Figure 29. The Template characters determine how special format characters are applied to the data.

When the Overlay option is used, special characters are treated as part of the data and overlay any other specific character in the given position. For example, when the Format expression is "999-999," and the data contains "123456," the report shows "123-56 ." Notice how the "4" is replaced by the dash in the format expression.

When the Interleave option is used, the special character is inserted in between existing characters in the data. For example, when the Format expression is "999-999," and the data contains "123456," the report shows "123-456." Notice that the dash is inserted between the "3" and the "4."

Trim Mode for Character Expressions

Prior to VFP 9.0, field objects were always trimmed to the nearest word when the text was too long. In VFP 9.0, a new option on the Field Properties dialog box allows you to determine how the text is trimmed (see Figure 30).

Figure 30. Use the Trim mode for character expressions to indicate the method used to trim long text.

The six trim options are as follows:

  • Select Default trimming to use the default behavior, which is the same as the Trim to nearest word, append ellipsis option. This behavior is similar to prior versions of VFP, with the exception of having the ellipsis appended.
  • Select Trim to nearest character to have the text trimmed to the last full character that fits in the defined area.
  • Select Trim to nearest word to have the text trimmed to the last full word that fits in the defined area.
  • Select Trim to nearest character, append ellipsis to have the text trimmed to the last full character that fits in the defined area, once an ellipsis (...) is added to the text that prints.
  • Select Trim to nearest word, append ellipsis to have the text trimmed to the last full word that fits in the defined area, once an ellipsis (...) is added to the text that prints.
  • Select Filespec: Show inner path as ellipsis to have the inner directories of a long path and filename replaced with an ellipsis (...) when the full text does not fit in the defined area.

Size and Position

Another new feature available on Layout objects is better control of the size and position of the object, as shown in Figure 31.

Figure 31. Use the Size and position in layout options on the Properties dialog box to control relative and absolute positioning.

When an object is added to the report, the values for From page top, From left, Height, and Width are automatically set. It is important to note that the From page top property is relative to the top of the page in the Report Designer, which means it takes into account the height of any gray bars above the object. Changing the From page top property may inadvertently move the object to another band.

Relative Positioning

The From page top property and the Height property work together to determine whether absolute positioning or relative positioning is used. When the From page top property is set to a value that falls within the Report Designer surface, and the value of the Height property is less than or equal to the height of the band the object is located in, relative positioning is used. Relative positioning is needed for objects in bands other than the Page Header and Page Footer.

Absolute Positioning

When the From page top property is set to a value that falls outside the Report Designer surface, or the value of the Height property is greater than the height of the band the object is located in, absolute positioning is used. Absolute positioning means the object is printed in exactly the same location on each and every page.

Absolute Positioning can be used to create a watermark on a report. Place a graphic image in the Page Header band, and set it to Scale contents, retain shape. Change the From page top property and the From left property to indicate the upper-left corner of where you want the watermark to begin. Change the Height and Width properties to indicate the overall size of the watermark, making sure not to extend beyond the printable margins of the printer.

International Features

A few changes have been made to VFP 9.0 to make reports more functional in international situations. Specifically, character sets, or language scripts, can be set for fonts. Units have more options, and the STRCONV() command has more options.

FontCharSet

The character set, or language script, of a font may be set in the Font dialog box, as shown in Figure 32. This can be set for a specific object on the report and it can also be set for the default font of the entire report.

Figure 32. Use the Script combo box to select a character set or language script.

Units

The Set Grid Scale dialog box has three additional Ruler Scale options to allow you to specifically set the scale to inches or metric/centimeters or to turn the ruler off. This gives you better control when you have customers with various system defaults. Figure 33 shows the new options in the Set Grid Scale dialog box.

Figure 33. Use the new drop-down combo box in the Set Grid Scale dialog box for better control over the ruler scale.

The same changes made to the Set Grid Scale dialog box have also been made to the Report tab of the Options dialog box.

STRCONV()

Another change to VFP 9.0 that helps with international reports is a change to the STRCONV() function. You can now use it to handle transformations using codepages and fontcharset values, along with locale IDs. The following Help documentation explains the new functionality of the STRCONV() command.

STRCONV(cExpression, nConversionSetting [,nRegionalIdentifier
 [,nRegionalIDType]])

nRegionalIDType: 
0 - (default) nRegionalIdentifier is LocaleID.
1 - nRegionalIdentifier is code page.
2 - nRegionalIdentifier is FontCharSet.

For nConversion settings 1, 2, 3, 4, 7, and 8, only nRegionalIdentifier=0 is supported

For designing non-English reports, the new improvements to the FontCharSet, the Units, and the STRCONV() command allow for more flexibility in design.

Printing Enhancements

Some existing commands and dialog boxes have been enhanced for better functionality. The SYS(1037) command has a new parameter and return value, the GetFont() command has a new style, and the APrinters() command has three new columns.

SYS(1037)

The SYS(1037) command is used to invoke the Print Setup dialog box, as well as change the VFP default printer. Prior to VFP 9.0, the SYS(1037) command had no significant return value. It always returned an empty string, regardless of what the user did. This made it impossible to know if the user pressed the Cancel button.

In VFP 9.0, a new parameter has been added to the SYS(1037) function as well as a meaningful return value (see Table 1.)

Table 1. New parameter and return value of SYS(1037)

Parameter Description Return Value
SYS(1037) Same behavior as prior versions, except it now returns a meaningful value. 0 = User canceled

1 = User selected OK

SYS(1037,1) If the current work area contains a structure matching that of an FRX structure, and no printer information is stored in the current work area, the Page Setup dialog box is invoked. If the user selects OK from the dialog box, VFP writes the EXPR, TAG, and TAG2 fields in the first record of the cursor, and then restores the cursor to the previous RECNO().

If the current work area does not contain the appropriate structure, no dialog box is invoked and zero is returned.

0 = User canceled or structure was not valid

1 = User selected OK, FRX updated accordingly

SYS(1037,2) If the current work area contains a structure matching that of an FRX structure, the VFP default printer information is written to the EXPR, TAG, and TAG2 fields of the first record, and then it restores the cursor to the previous RECNO().

If the current work area does not contain the appropriate structure, no information is written to the cursor and zero is returned.

0 = No action was taken, structure invalid

1 = VFP Default Printer information was successful saved to the FRX

SYS(1037,3) If the current work area contains the structure matching that of an FRX structure, the Printer Environment of the FRX is saved as the new VFP default printer. In addition, it rewrites the printer environment to the FRX, just in case there was any invalid information.

If the current work area does not contain the appropriate structure, no action is taken and the zero is returned.

0 = No action was taken

1 = VFP Default Printer information was set from the FRX

GetFont()

A few slight changes have been made to the GetFont() command.

Printable Fonts Only

The third parameter of GetFont() has a new value. Passing P tells VFP to only display the printable fonts for the default printer, as shown below.

=GetFont(' ', 0, 'P')

FontCharSet

As in previous versions of VFP, the fourth parameter of GetFont() is used to identify the FontCharSet. However, a slight change has been made to the meaning of passing 0 or 1 as the fourth parameter.

  • Passing 0 enables the Script combo box, explicitly sets "Western script," and returns the FontCharSet along with the other data.
  • Passing 1 enables the Script combo box, sets the value to the user's regional settings, and returns the FontCharSet along with the other data.

As in previous versions, omitting the fourth parameter disables the Script combo box and does not return the FontCharSet as part of the return value.

APrinters()

A new parameter has been added to the APrinters() command to gather information about the printers. Using the optional second parameter, as shown below, causes the array to be populated with three additional columns.

lnPrinters = APrinters(laPrinters, 1)

The first two columns are the same as in prior versions; Name of Printer and Printer Port. The three new columns are Driver, Comment, and Location.

Calling APrinters() without the optional second parameter provides the same behavior as in prior versions; that is, two columns are returned.

Modern Dialog Boxes

The Print Setup dialog box has been renamed to Page Setup and it has been modernized. The Printer dialog box has also been modernized when run under Windows 2000 or later operating systems.

Page Setup dialog box

The Page Setup dialog box, shown in Figure 34, can be invoked by any of the following methods:

  • When the Report Designer is not WONTOP(), select Page Setup from the File menu.
  • When the Report Designer is WONTOP(), select the Page Setup button from the Report Page Setup dialog box.
  • Use SYS(1037).

Figure 34. The new Page Setup dialog box replaces the older Print Setup dialog box.

Print Dialog Box

The Print dialog box, shown in Figure 35, can be invoked by any of the following methods:

  • Select Print from the File menu.
  • Use the TO PRINTER PROMPT clauses in a command, such as REPORT FORM.

Figure 35. The new Print dialog box has a more modern look to it when run under Windows 2000 or later.

Data Group Enhancements

A few enhancements have been made to Data Groups in the VFP 9.0 Report Writer.

Maximum Data Groups

The maximum number of Data Groups has been increased from 20 to 74.

Horizontal Columns

Previously, reports with more than one column defined as horizontal with a Data Group, wasted a lot of space. The first position (row 1, column 1) was left blank and data began in column 2 of row 1. Also, a blank band was wasted in between each set of Data Groups, as shown in Figure 36. Even if the height of the Data Group Header band is zero, VFP still reserved the space, as shown in Figure 37.

Click here for larger image

Figure 36. Prior versions of VFP wasted a lot of space when using horizontal columns with Data Groups. (Click image for a larger view.)

Click here for larger image

Figure 37. Prior versions of VFP reserved space for Data Group Headers, even when none where defined. (Click image for a larger view.)

In VFP 9.0, the behavior of Data Groups and horizontal columns has been changed. When a new Data Group is encountered, it is printed in column 1 of the next full row. The remainder of this row is left blank and not used for printing details. The details belonging to the Data Group begin in column 1 of the row immediately after the row the Data Group is printed in, as shown in Figure 38. Also, no extra space is reserved if the height of the Data Group Header band is zero, as shown in Figure 39.

Click here for larger image

Figure 38. VFP 9.0 does not waste as much space as prior versions when horizontal columns and Data Groups are used. (Click image for a larger view.)

Click here for larger image

Figure 39. VFP 9.0 does not reserve extra space when the Data Group Header band is 0" tall. (Click image for a larger view.)

The new behavior, although avoiding the previously described situation, may break some existing reports. However, an added benefit of the new behavior is that the Data Group band can be stretched across all the columns, as shown in Figure 40.

Click here for larger image

Figure 40. In VFP 9.0, you can expand the Data Group Header band across multiple columns. (Click image for a larger view.)

Multiple-Detail Bands

Besides the extensibility enhancements in the VFP 9.0 Report Writer, the new multiple-detail band feature is one of the biggest, and most often requested, improvements. The new feature allows you to process multiple child tables for each record in a parent table. An example of this type of report is shown in Figure 41.

Click here for larger image

Figure 41. This sample multiple-detail band report has three separate detail bands for each customer. (Click image for a larger view.)

Tables and Relations

Understanding how the parent and child tables work together are key to understanding how to use this new feature. As an example of a multiple-detail scenario, assume you are writing the report shown in Figure 41. The database for this scenario is shown in Figure 42.

Figure 42. A sample database of Customers, Members, Vehicles, and Homes for an insurance company.

The Customer table is the parent table and contains one record for each customer of the insurance company. The Members, Vehicles, and Homes tables are child tables of the Customer table. The Members table holds one record for each family member of the customer. The Vehicles table holds one record for each vehicle insured by the customer. The Homes table holds one record for each home insured by the customer.

Driving the Report

One table is necessary to drive the report. In this example, the Customer table is the driving table. If you use the report's Data Environment to define the tables, set the InitialSelectedAlias property to this table. If you are using code to define the tables, make sure the Customer table is the current work area at the time the report is run.

The "Target Alias"

The target alias is the term used to describe which table is the driving table for a particular detail band. In this example, the Members table is the target alias for detail 1 band, the Vehicles table is the target alias for detail 2 band, and the Homes table is the target alias for detail 3 band.

If no target alias is defined for a detail band, the behavior it takes on is that of prior versions of VFP. In other words, one detail band is processed per parent record. However, if you enter the name of the parent table as the target alias, you will get very different results. For each record in the parent table, VFP processes through all records in the entire parent table, printing each parent record in the detail band. Therefore, if you have a table with 10 parent records, and you set the target alias of a detail band to the parent table, the final report prints 10 sets of 10 records, or a total of 100 records.

Relations

It is important to realize that relations play a big part in how multiple-detail bands operate. VFP uses the relations between the parent table and the child tables to navigate through the records. You may use SET RELATION or SET SKIP to define these relations. If you are opening the tables in the Data Environment, and relations are already defined in the database, these relations are honored.

If you are opening the tables in code, the following example shows how to set up the tables for the Insurance Customer Listing shown in Figure 41.

*-- Open the child tables
USE Members IN 0 ORDER CustomerFK
USE Vehicles IN 0 ORDER CustomerFK
USE Homes IN 0 ORDER CustomerFK

*-- Open the parent table
SELECT 0
USE customer ORDER CustomerPK

*-- Set the relations between the parent and children
SET RELATION TO CustomerPK INTO Members
SET RELATION TO CustomerPK INTO Vehicles ADDITIVE
SET RELATION TO CustomerPK INTO Homes ADDITIVE

*-- Run the report
REPORT FORM Insurance PREVIEW

Defining Multiple-Detail Bands

By default, new reports are created with one detail band.

Adding Additional Detail Bands

Additional detail bands are added through the Optional Bands dialog box shown in Figure 43. To invoke this dialog box, select Optional Bands... from the Report menu. This is the same dialog box that was formerly named Title/Summary. It has been renamed to better fit the additional option added to it.

Figure 43. Use the Details spinner on the Optional Bands dialog box to adjust the total number of detail bands.

Increase the Details spinner to the total number of detail bands you want on the report. You may define up to 20 detail bands for each report. Figure 44 shows how the Report Designer looks after choosing three detail bands.

Click here for larger image

Figure 44. This sample report has three detail bands defined. (Click image for a larger view.)

Defining the Target Alias

The target alias is assigned to a detail band through the Detail dialog box (see Figure 45). This dialog box can be invoked by selecting Edit Bands... from the Report menu and selecting the applicable detail band. You can also invoke this dialog box by double-clicking the gray bar of the applicable detail band.

Figure 45. Define the "Target alias" for each detail band on the applicable Detail dialog box.

The Target alias is an expression; therefore, you must wrap the table name in quotes. Once you have each target alias defined, the gray bars representing the detail bands show the target alias (see Figure 46).

Click here for larger image

Figure 46. The Report Designer identifies each detail band with a number and the target alias associated with it so you can easily identify different detail bands. (Click image for a larger view.)

When creating multiple-detail band reports, it is important to prefix field names with the applicable alias name. This prevents any confusion as to which table a field comes from.

Headers and Footers

Another feature of the multiple-detail band enhancement is the ability to add headers and footers to each detail band. These are similar to group headers and footers in some ways, yet different in others. For each parent record that is processed, the following occurs:

  • The detail 1 header band is processed.
  • The detail 1 band is processed once for each child record in the associated target alias
  • The detail 1 footer band is processed.
  • The detail 2 header band is processed.
  • The detail 2 band is processed once for each child record in the associated target alias.
  • The detail 2 footer band is processed.
  • The detail 3 header band is processed.
  • The detail 3 band is processed once for each child record in the associated target alias.
  • The detail 3 footer band is processed.

To turn on detail headers and footers, Place a check mark in the selection box for Detail Header/Footer in the Detail dialog box for each of the detail bands (see Figure 45). To help sort out the detail bands from other bands, the triangle preceding the band name is solid, where the other triangles are clear (see Figure 47).

Click here for larger image

Figure 47. The detail bands are marked with solid triangles and all other bands are marked with open triangles. (Click image for a larger view.)

In addition to the Report Designer identifying each detail band, the Edit Bands dialog box also indicates each detail header band, detail footer band, and detail band by using the sequential number of the band. The Edit Bands dialog box can be invoked by selecting Edit Bands... from the Report menu (see Figure 48).

Figure 48. The Edit Bands dialog box uses each detail band's sequential number to help identify each detail band, detail header band, and detail footer band.

It is important to note that even if no detail records exist for a particular detail band, the associated detail header and detail footer bands still print. If you do not want the detail header and detail footer bands under this condition, you may use the following Print when logic in each layout object defined in the bands to suppress their printing. Be sure to place a check mark in the selection box for Remove line if blank for these layout objects as well.

NOT EOF(<target alias>)

Similar to group headers and footers, detail headers and footers have some of the same options. As seen in Figure 45, the Detail dialog box has many new options:

  • Start on a new column: Use this option to have the detail set start on a new column of the report. Note that this option does allow you to specifically assign a detail set to a specific column. If one detail set has enough information to overflow the column, it is continued in the next column.
  • Start on a new page: Use this option to have the detail set start on a new page.
  • Reset page number to 1 for each detail set: Use this option, along with the Start on a new page option, to reset the page number to 1 for each new detail set.
  • Start detail set on new page when less than: Use this option to help prevent orphans. The detail set begins on a new page if the indicated amount of space is not available.
  • Detail Header/Footer: Use this option to add a detail header and detail footer band around this detail band.
  • Reprint detail header on each page: Use this option, along with the Detail Header/Footer option, to have the detail header band reprint whenever the detail set overflows to a new page.

Report Variables and Calculations

With the introduction of multiple-detail bands, report variables and calculations have some new twists to them. You need to fully understand how they are processed in order to use them effectively. Otherwise, you may not get the results you are expecting.

The Reset at prompt on the Report Variables dialog box has been renamed to Reset based on. This more clearly defines that the variable is reset based on the change in value of the selected option. In addition to renaming the control, if more than one detail band is defined in the report, each detail band is added to the drop-down list. See Figure 49 for a look at the new Report Variables dialog box.

Figure 49. Calculated report variables have some new "Reset based on" options.

Selecting Detail on as the Reset based on value, tells VFP to only process this calculation when processing the detail records in the target alias of this detail band. The report variable is not altered while records in other target aliases are being processed. This allows you to tie a report variable to one particular detail band. The value of the report variable is not cleared until the detail header band of this same detail set is processed for the next parent record.

If you chose a Reset based on value other than one of the detail bands, the calculation is processed in several places. First, for each parent record, the calculation is applied. Next, the calculation is applied for each record in the target alias of the first detail band. Then the calculation is applied for each record in the target alias of the second detail band, and so on.

In the two-page report shown in Figure 50, you can see an example of calculated report variables associated with individual detail bands. You can also see the Total records processed at the end of the report shows a value of 20. This number represents the total Members processed (7), plus the total Vehicles processed (7), plus the total Homes processed (3), plus the total Customers processed (3).

Click here for larger imageClick here for larger image

Figure 50. Calculated report variables can be associated with a detail band or can apply to all records processed. (Click images for larger views.)

Miscellaneous

There are a few other miscellaneous items to explain in regards to multiple-detail bands.

FRX Storage

Bands are stored in the FRX with an OBJTYPE value of 9, and an OBJCODE value that determines what type of band the record is. Detail header bands are stored with an OBJCODE value of 9, and detail footer bands are stored with an OBJCODE value of 10.

The new target alias expression is stored in the EXPR field of the applicable detail band record.

SUMMARY Issues

Using the SUMMARY clause of the REPORT FORM command prevents the detail band from printing, yet all the page headers and footers, column headers and footers, and group headers and footers are printed. Any On Entry or On Exit expressions in a detail band are not processed when the SUMMARY clause is used. When issuing SUMMARY on a multiple-detail band report, the detail headers, detail footers, and detail bands are not processed.

A Lot to Learn

Getting your hands around multiple-detail bands can take a lot of time. You have to understand how all the tables work together, know what a target alias is, and understand relations between tables. You also have to get a handle on how variables and calculations are affected by multiple-detail bands. You may have to read through this section more than once before it all sinks in.

The FRX

To maintain backward compatibility, the VFP 9.0 Report Writer uses the same FRX structure as in previous versions. For each record in the FRX, the OBJTYPE and OBJCODE fields are used together to define what type of data is contained in the record. Not all fields in the FRX apply to all types of records. Therefore, to accommodate all the new features in the VFP 9.0 Report Writer, existing fields are overloaded when necessary.

Another key change to the VFP 9.0 Report is the way the USER field is treated. Prior to VFP 9.0, any data stored in the USER field was erased. This behavior defeated the purpose of the USER field and rendered it unusable. In VFP 9.0, any data stored in the USER field is retained and left alone. You can also create additional fields in the FRX, as long as they are added to the end of the FRX. Any additional fields are retained by VFP and will not be deleted.

In addition to retaining the USER field, the VFP 9.0 Report Writer now retains any records of unknown types. Instead of deleting them from the FRX, the Report Writer retains these records at the end of the FRX table and ignores these records during processing. This gives you the ability to add your own record types for special processing.

Theoretically, you can also write reports in VFP 9.0, and as long as you do not use any new features, you can run the reports in prior versions of Visual FoxPro. Of course, if you add new fields or records to the FRX, they are destroyed if you edit and save the report in a prior version of VFP.

The Records

There are several different types of records stored in the report metadata. The OBJTYPE field identifies what type each record is and the rest of the information in the record varies greatly, depending on the OBJTYPE. In other words, the fields in the table have multiple purposes and you need to know the OBJTYPE to decipher the meaning of the rest of the record. The valid types are as follows:

  • Report definition (OBJTYPE = 1): The first record in the table is a report definition record. It contains general information about the overall report, such as printer information and page setup information. There's one report definition record per table.
  • Report objects: Several different types of objects are used to portray text, data, and graphics on a report. Collectively, these objects are referred to as Report objects and they consist of the following five types.
    • Label (OBJTYPE = 5): A label object is a term used to describe a static piece of text put on a report. It is commonly used for report titles, column titles, company name, and other information that does not change each time the report is printed. Each label object on a report is represented by one record.
    • Line (OBJTYPE = 6): A line object is used to represent horizontal and vertical lines on a report. Each line object on a report is represented by one record.
    • Shape (OBJTYPE = 7): A shape object is used to represent rectangles and rounded rectangles on a report. Each shape object on a report is represented by one record.
    • Field (OBJTYPE = 8): A field object is one of the most commonly used objects on a report. It is used to print data on a report. The data can be a field from a table or the results of an expression. It can even use the internal calculations provided by the VFP Report Writer to obtain the results. Each field object on a report is represented by one record.
    • Picture (OBJTYPE = 17): A picture object is used to represent a Picture/ActiveX Bound control on a report. Each Picture/ActiveX object on a report is represented by one record.
  • Band (OBJTYPE = 9): A band object is used to represent an individual band on a report. As a minimum, all reports have three band objects: page header, detail, and page footer. A report can also contain several optional bands: title, column header, data group header, column footer, data group footer, summary, detail header, and detail footer.
  • Group (OBJTYPE = 10): A group object is used to represent a group of report objects that have been grouped together using the Group option from Format menu from within the Report Designer (do not confuse this with data groups).
  • Variable (OBJTYPE = 18): A variable object is used to represent an individual report variable. Each report variable on a report is represented by one record.
  • Font (OBJTYPE = 23): A font object is used to represent a unique font used somewhere on the report. Each different font used on the report is represented by one font object record. At a minimum, one font object exists (for the default font).
  • Data Environment (OBJTYPE = 25): A data environment object is used to represent the data environment of a report. All properties and method code of the data environment are stored in this record. There is one data environment record per table.
  • Data (OBJTYPE = 26): A data object is used to represent either a cursor object or a relation object. Each cursor or relation that is defined in the data environment of a report is represented by one record.

The records are placed in the table in a specific physical order and it is important to honor that order if you programmatically add new records. You can use the SORT command to copy the records to a temporary table and then back to the report table in the correct order, which is as follows:

  • The report definition record (OBJTYPE = 1)
  • The band records (OBJTYPE = 9). The bands are added to the table in ascending order of the OBJCODE field, with the following exceptions:
    • When multiple data groups are defined on the report...

      ...the group header bands (objcode = 3) are added in the same order they appear on the Data Grouping dialog box.

      ...the group footer bands (objcode = 5) are added in the opposite order they appear on the Data Grouping dialog box.

    • When multiple-detail bands are defined on the report, the first detail band's detail header, detail, and detail footer bands are added as a set. Then the second detail band's set of records are added, and so on.
  • The report objects (OBJTYPE = 5, 6, 7, 8 and 17) are added in the order of their Z-Order, with the bottommost object added first.
  • Group records (OBJTYPE = 10)
  • Report variable records (OBJTYPE = 18). The report variable records are added to the table in the same order as they appear on the Report Variable dialog box.
  • Font records (OBJTYPE = 23)
  • The data environment record (OBJTYPE = 25)
  • The data records (OBJTYPE = 26) are added in the order they are added to the data environment.

The Unit of Measure

Visual FoxPro uses its own unit of measure, the FoxPro Report Units (FRU), when referring to the size and placement of objects on the report. If your system is set up with inches, the unit of measure is 1/10,000 of an inch. If your system is set up with centimeters, the unit of measure is 1/1,000 of a centimeter.

The Position

There is no field in the table that represents what band an object belongs to. Instead, Visual FoxPro determines the band by calculating the defined height of each band, the VPOS of the object, and then determines which band a particular VPOS falls into.

When looking at the height of each band, however, VFP also takes into account the height of the horizontal gray bar that represents each band when displayed on the screen by the Report Designer. The value for the height of the horizontal gray bar is 2083.33333333 when using inches and 529.16666667 when using centimeters.

The Fields

Describing what each field represents is difficult because fields can be used for different purposes, depending on what the OBJTYPE is of the particular record. Table 2 lists each field in the table and what the meaning is for the different types of objects.

In addition to Table 2, Microsoft has provided a DBF that contains information about FRX tables. This DBF has been updated for VFP 9.0 and it is located in the HOME() + 'tools\filespec' directory.

Table 2. The table structure of a VFP 9.0 report (FRX)

Field OBJTYPE Description
PLATFORM All Always "WINDOWS"
UNIQUEID All except:

0-Comment

23-Font

25-Data Environment

26-Data

This is a unique identifier for most records. You can use SYS(2015) to create your own unique value when adding records.
TIMESTAMP All except:

21-Printer driver (2.x)

23-Font

25-Data Environment

26-Data

A time stamp of when this record was last changed.
OBJTYPE   0-49 reserved for native use only.

50-99 available for custom use.

0 = Comment

1 = Report Definition

2 = Work area (2.x reports)

3 = Index (2.x reports)

4 = Relations (2.x reports)

5 = Label

6 = Line

7 = Shape

8 = Field

9 = Band

10 = Grouped objects (not Data Groups)

17 = Picture / OLE Bound

18 = Variable

21 = Printer driver setup (2.x reports)

23 = Font

25 = Data Environment

26 = Data (Cursor, Relation, or cursor adapter)

OBJCODE   When the OBJTYPE field alone is not enough to identify a type of record, the OBJCODE field is used to further identify a type of record.
  1-Report Definition Always 53.
  2-Work area (2.x) Work area of the table.
  3-Index (2.x) Work area of the IDX.
  4-Relation (2.x) Work area of the child table.
  5-Label

6-Line

8-Field

10-Group

17-Picture

Always 0.
  7-Shape Always 4.
  9-Band Describes the type of band:

0 = Title

1 = Page Header

2 = Column Header

3 = Group Header

4 = Detail

5 = Group Footer

6 = Column Footer

7 = Page Footer

8 = Summary

9 = Detail Header

10 = Detail Footer

NAME 2-Work area (2.x) File name of table.
  3-Index (2.x) File name of IDX file.
  8-Field The Design-time caption.
  17-Picture If defined as Picture from File, and a picture file is chosen, this is blank.

If defined as Picture from File, and an expression is entered, this contains the expression.

If defined as Picture from Field, this contains the name of the general field.

  18-Variables Variable name.
  21-Printer driver (2.x) Name of the setup.
  25-Data Environment "dataenvironment"
  26-Data "cursor" for cursors

"relation" for relations

"cursoradapter" for cursor adapters

EXPR 1-Report Definition Printer driver and printer setup information.
  3-Index (2.x) The order expression.
  4-Relation (2.x) The relation expression.
  5-Label The text of the Label object.
  8-Field The expression of the Field object.
  9-Band/Group Header The Data Group expression.
  9-Band/Detail The Target alias expression.
  18-Variables The Value to store expression.
  25-Data Environment

26-Data

The properties of the Data Environment or Data object.
VPOS 1-Report Definition Number of column sets.
  10-Group This number represents the first object included in this group. It is based on the Z-Order of the report objects. However, grouped objects can belong to other grouped objects. When this occurs, the entire group of objects is only counted once when determining this number.
  23-Font Character height in pixels, FONTMETRIC(1).
  Report objects The vertical position of the object, in FRUs.
HPOS 1-Report Definition Left margin, in FRUs.

Relative to the printable margin if Printable page is chosen.

Relative to the physical edge of the paper if Whole page is chosen.

  10-Group This number represents the total number of report objects in this group. However, if grouped objects are included in another group, the entire group is only counted as one object.
  23-Font The average character width in pixels, FONTMETRIC(6).
  Report objects The horizontal position of the object, in FRUs.
HEIGHT 1-Report Definition Spacing between columns, in FRUs.
  9-Band Height of the band, in FRUs.
  23-Font Character ascent in pixels, FONTMETRIC(2).
  Report objects Height of the object, in FRUs.
WIDTH 1-Report Definition Width of each column, in FRUs.
  9-Band/Detail

9-Band/Group Header

Corresponds to the Start group on new page when less than value on the Data Grouping dialog box or Detail dialog box, in FRUs.
  23-Font Maximum character width in pixels, FONTMETRIC(7).
  Report objects Width of the object, in FRUs.
STYLE 1-Report Definition If the report uses a DataEnvironment class or has copied a Data Environment from another report, this contains XML data about the Data Environment.
  2.x report objects B = Bold

I = Italic

R = Raised

L = Lowered

J = Right-align

C = Center-align

PICTURE 5-Label Contains alignment formatting characters.
  8-Field Corresponds to the expression entered into the Format text box on the Report Expression dialog box.

If Interleave is selected, the format expression is prefixed with @R.

  17-Picture If defined as Picture from File, and a picture file is chosen, this contains the relative path name for the file.

If defined as Picture from File, and an expression is entered, this is blank.

If defined as Picture from Field, this is blank.

ORDER All—pre VFP 9.0 Not used.
  All—VFP 9.0 Contains a character value representing a numeric value (summed binary flags) to identify protection features.

Objects (bit, value, meaning)

0, 1, Lock (moved or resized)

1, 2, Hide (visible)

2, 4, No Delete

3, 8, No Edit

6, 64, No Select

Bands (bit, value, meaning)

4, 16, No Edit

14, 16384, No Resize

Report (bit, value, meaning)

7, 128, No Preview

8, 256, No Optional Bands

9, 512, No Data Grouping

10, 1024, No Variables

11, 2048, No Page Layout

12, 4096, No Multiple Select

13, 8192, No Data Environment

15, 32768, No Print

16, 65536, No Quick Report

UNIQUE 1-Report Definition .T. = Temporary wizard generated report

.F. = Permanent report

  2-Work area (2.x) .T. = An index is in use for this work area

.F. = An index is NOT in use for this work area

  18-Variable Corresponds to the Release after report check box on the Report Variables dialog box.
COMMENT All Corresponds to the Comments edit box.
ENVIRON 25-Data Environment .T. = Private Data Session

.F. = Default Data Session

BOXCHAR All Not used.
FILLCHAR 8-Field C for character fields.

N for numeric fields.

D for date fields.

TAG 1-Report Definition Binary printer driver information.
  2-Work area (2.x) Alias of the work area.
  9-Band The On Entry expression.
  18-Variable The Initial value.
  25-Data Environment

26-Data

Contains event and method code.
TAG2 1-Report Definition Binary printer driver information.
  9-Band The On Exit expression.
  25-Data Environment

26-Data

Contains the compiled event and method code.
PENRED 23-Font The character descent in pixels, FONTMETRIC(3).
  Report objects The foreground Red value, as in RGB().
PENGREEN 23-Font Extra leading in pixels, FONTMETRIC(5).
  Report objects The foreground Green value, as in RGB().
PENBLUE Report objects The foreground Blue value, as in RGB().
FILLRED Report objects The background Red value, as in RGB().
FILLGREEN Report objects The background Green value, as in RGB().
FILLBLUE Report objects The background Blue value, as in RGB().
PENSIZE 6-Line

7-Shape

Pen size (set when you select Pen from the Format menu and choose one of the solid-lined pens).

0 = Hairline

1 = 1 Point

2 = 2 Point

4 = 4 Point

6 = 6 Point

The full line thickness will not be visible unless the HEIGHT or WIDTH is set to (PENSIZE x 104.167).

PENPAT 6-Line

7-Shape

Pen pattern (set when you select Pen from the Format menu and choose one of the non-solid-lined pens).

0 = None

1 = Dotted

2 = Dashed

3 = DashDot

4 = DashDotDot

8 = Normal/Solid

FILLPAT 7-Shape Fill pattern (Select Fill from the Format menu).

0 = None

1 = Solid

2 = Horizontal lines

3 = Vertical lines

4 = Diagonal lines, leaning left

5 = Diagonal lines, leaning right

6 = Grid (horizontal and vertical lines)

7 = Hatch (left and right diagonal lines)

FONTFACE 1-Report Definition The font name of the Default Font.
  5-Label

8-Field

23-Font

The font name.
FONTSTYLE 1-Report Definition

5-Label

8-Field

23-Font

0 = Normal

1 = Bold

2 = Italic

4 = Underlined

128 = Strikethrough

The above numbers can be combined together to achieve multiple font styles.

FONTSIZE 1-Report Definition

5-Label

8-Field

23-Font

The font size.
MODE Report objects Mode

0 = Opaque

1 = Transparent

Reading Order

0 = Left-to-Right

2 = Right-to-Left

4 = Context

Mode and Reading Order values are added together.

RULER 1-Report Definition 0 = No ruler

1 = Ruler measurement is inches

2 = Ruler measurement is metric

3 = Ruler measurement is pixels

4 = Ruler measurement is character (1/12")

5 = Ruler respects current system default

RULERLINES 1-Report Definition 0 = Do not show the grid lines in the Report Designer

1 = Show the grid lines in the Report Designer

  8-Field Corresponds to the Trim mode for character expressions option on the Format dialog box.

0 = Default trimming

1 = Trim to nearest character

2 = Trim to nearest word

3 = Trim to nearest character, append ellipsis

5 = Show inner path as ellipsis

6 = Trim to nearest word, append ellipsis

GRID 1-Report Definition .T. = Snap to Grid is on

.F. = Snap to Grid is off

GRIDV 1-Report Definition Vertical spacing of grid lines, in pixels.
GRIDH 1-Report Definition Horizontal spacing of grid lines, in pixels.
FLOAT Report objects Corresponds to the Float option on the object's Property dialog box.
STRETCH 6-Line

7-Shape

Corresponds to the Stretch relative to height of band check box on the object's Property dialog box.
  8-Field Corresponds to the Stretch with overflow check box on the object's Property dialog box.
STRETCHTOP 6-Line

7-Shape

Corresponds to the Stretch relative to tallest object in group check box on the object's Property dialog box.
TOP 1-Report Definition .T. = Print area is Whole page

.F. = Print area is Printable page

  Report objects Corresponds to the Fix relative to top of band option on the object's Property dialog box.
BOTTOM 1-Report Definition .T. = Multiple column sets are printed in left-to-right order

.F. = Multiple column sets are printed in top-to-bottom order

  Report objects Corresponds to the Fix relative to bottom of band option on the object's Property dialog box.
SUPTYPE All Not used.
SUPREST All Not used.
NOREPEAT Report objects Corresponds to the Remove line if blank check box on the Print when dialog box.
  9-Bands/Detail Corresponds to the Repeat detail header on each page check box on the Detail dialog box.
RESETRPT All Not used.
PAGEBREAK 9-Band/Title Title page is printed on its own page.
  9-Band/Group Header Corresponds to the Start each group on a new page check box on the Data Grouping dialog box.
  9-Band/Group Footer Matches the corresponding group header record.
  9-Band/Summary Summary page is printed on its own page.
  9-Band/Detail Header Corresponds to the Start on a new page check box on the Detail dialog box.
  9-Band/Detail Footer Matches the corresponding detail header record.
COLBREAK 9-Band/Group Header Corresponds to the Start group on new column check box on the Data Grouping dialog box.
  9-Band/Group Footer Matches the corresponding group header record.
  9-Band/Detail Header Corresponds to the Start on a new column check box on the Detail dialog box.
  9-Band/Detail Footer Matches the corresponding detail header record.
RESETPAGE 9-Band/Group Header Corresponds to the Reset page number to 1 for each group check box on the Data Grouping dialog box.
  9-Band/Group Footer Matches the corresponding group header record.
  9-Band/Detail Header Corresponds to the Reset Page Number to 1 for each Detail Set check box on the Detail dialog box.
  9-Band/Detail Footer Matches the corresponding detail header record.
GENERAL 17-Pictures Clip/Scale setting:

0 = Clip

1 = Scale retain shape

2 = Scale and fill frame

SPACING 5-Label 0 = Single

1 = 1.5

2 = Double

  8-Field Always set to 0.
DOUBLE 17-Pictures Corresponds to the Center picture check box on the object's Property dialog box.
  1-Report Definition

Report objects

.T. indicates FontCharSet applies to this object (See RESOID)
SWAPHEADER All Not used.
SWAPFOOTER All Not used.
EJECTBEFOR 9-Band/Summary Print page header.
EJECTAFTER 9-Band/Summary Print page footer.
PLAIN 1-Report Definition Corresponds to the Add non-selected alias only option button in the Expression Builder Options dialog box. (A value of .T. takes precedence over the value of ADDALIAS.)
  9-Band .T. = Constant band height
SUMMARY All Not used.
ADDALIAS 1-Report Definition Corresponds to the Aliases option group in the Expression Builder Options dialog box.

.T. if Always add alias option button is selected.

.F. if Never add alias option button is selected. (A value of .T. in the PLAIN field takes precedence over this value.)

OFFSET 6-Line Always 1.
  7-Shape The radius used on Rounded Rectangle objects (default dialog box uses 12, 16, 24, 32, and 99).
  8-Field 0 = Align left

1 = Align right

2 = Align center

  17-Picture Indicates File or General Field:

0 = Filename (stored in PICTURE field)

1 = General field (stored in NAME field)

2 = Expression (stored in NAME field)

TOPMARGIN All Not used.
BOTMARGIN All Not used.
TOTALTYPE 8-Field

18-Variable

Type of calculation:

0 = Nothing

1 = Count

2 = Sum

3 = Average

4 = Lowest

5 = Highest

6 = Standard deviation

7 = Variance

RESETTOTAL When TOTALTYPE<>0

8-Field

18-Variable

Determines when calculations are reset:

1 = At end of report

2 = At end of page

3 = At end of column

5+ = At end of data group where is the data group number (for example, 6 resets the calculation at Data Group 1, 7 resets the calculation at Data Group 2, and so on).

79+ = At end of detail band sets where is the detail band number (for example, 80 resets the calculation at Detail Set 1, 81 resets the calculation at Detail Set 2, and son on).

  When TOTALTYPE=0

8-Field

If one detail band exists:

1 = Reset at innermost group/band

If multiple detail bands exist:

1 = Reset at object's detail band

  When TOTALTYPE=0

18-Variable

1 = Reset at end of report
RESOID 1-Report Definition

Report objects

Indicates the FontCharSet that applies to this object (or the overall report).
CURPOS 1-Report Definition .T. = Show position is ON

.F. = Show position is OFF

SUPALWAYS 7-Shape Corresponds to the Print repeated values option group on the Print when dialog box, but it is backwards (note that this field and the SUPVALCHG field are set for shapes).

.T. = No

.F. = Yes

SUPOVFLOW Report objects Corresponds to the When detail overflows to new page/column check box on the Print when dialog box.
SUPRCOL Report objects Corresponds to the In first whole band of new page/column check box on the Print when dialog box (0 = unchecked, 3 = checked).
SUPGROUP Report objects Corresponds to the When this group changes drop-down combo box.

The number is 5+ the group number (for example, a 6 reprints at Data Group 1, a 7 reprints at Data Group 2, and so on).

SUPVALCHG Report objects Corresponds to the Print repeated values option group on the Print when dialog box, but it is backwards.

.T. = No

.F. = Yes

SUPEXPR Report objects Corresponds to the Print only when expression is true text box on the Print when dialog box.
USER All Available for the developer to use.

Conclusion

The VFP 9.0 Report Writer has many new features to help you create better reports. The Extensibility features expose the inner workings of the VFP Report Writer. The new reusable data environments allow you to share data environments between reports. Various aspects of reports, such as objects and bands, can be protected. A better development experience has been created through the new user interface. The new object layout enhancements, international features, printing enhancements, and data group enhancements offer more options than previously available. And finally, the new multiple-detail band feature opens up many more reporting options. Together, all these improvements and enhancements give you the ability to create more complex reports than ever before.

Bio

Cathy Pountney is a Microsoft Visual FoxPro MVP and has been developing software for 22 years, thirteen of which were as an independent consultant specializing in FoxPro. In 2001 she had the privilege of spending six months as a contractor onsite in Redmond with the Microsoft Fox Team. Currently she works for Optimal Solutions developing VFP applications for schools. Cathy has spoken at many FoxPro conferences and user groups across the U.S., written articles for various magazines, and her book, The Visual FoxPro Report Writer: Pushing it to the Limit and Beyond, is available from Hentzenwerke Publishing. You can contact Cathy at cathy@frontier2000.com, view her website at www.frontier2000.com, and view Optimal's website at www.optimalinternet.com.

Show: