Advice, tips, techniques and downloads for Visual Foxpro developers.
Home | Contact
Taming the Visual FoxPro report preview window
How to improve the way your VFP reports appear on the screen
When you preview a report in Visual FoxPro, the output appears in a window
like the one in Figure 1. Many users dislike this preview window, to such an
extent that developers often feel compelled to find alternative ways of
displaying their reports on the screen.
These are some of the things that users and developers dislike about the
default preview window:
- Users frequently click on the preview expecting to select some text, and are disconcerted to
find that this causes the zoom level to change.
- Users navigate the preview via the report
toolbar. If the user accidentally closes the toolbar (and users often do),
there’s no immediate way of getting it back.
- The preview window doesn’t consistently
remember its size, position or zoom factor (these settings are stored in the
resource file, which might not be available at run time).
- You can’t easily control the window size,
position or zoom factor programmatically.
- In VFP 8.0 and below, there are only five zoom
levels, with no whole-page option. This has increased to a more useful nine
in VFP 9.0, but still without a whole-page view.
- You can only view one page at a time. In some
situations, users might prefer to view two pages side by side (for example,
where the report is to be printed as a bound book), or perhaps even four
pages at a time.
In this article, we’ll suggest ways in which you can improve the default
preview window, or replace it with a custom-built report viewer of your own.
Most of the techniques we describe are only available in VFP 9.0, but we’ll
start with one that’s been around since version 5.0.
The IN WINDOW option
VFP’s REPORT FORM command includes an IN WINDOW clause that lets you host the
preview window in your own form. This isn’t quite as wonderful as it first
sounds, but it does open the way to a few useful enhancements.
To take advantage of this feature, first launch a form and make it visible.
Adjust its size, position and other properties as necessary. Then execute the
report, passing the name of the form (that is, the value of its Name property)
to the IN WINDOW clause:
LOCAL loPreview loPreview = CREATEOBJECT("Form") * At this point, you can customise the form in * certain ways, for example by changing its * size, position, caption or icon. loPreview.Caption = "Report Viewer" loPreview.Name = "MyPreview" loPreview.Visible = .T. REPORT FORM MyReport PREVIEW IN WINDOW MyPreview
This example uses the built-in form class as the basis for the preview form,
but you can use your own custom class if you prefer. By default, the preview
will be modal (regardless of the form’s WindowType property) and also
non-resizable. The preview will fill the form, so any other controls on the form
will be obscured.
You can change that behaviour by adding NOWAIT to the REPORT FORM command.
This will make the form modeless and resizable (in fact, you can resize the
preview area independently of the outer form). But keep in mind that when the
variable holding the form object (loPreview in this example) goes out of scope,
the form will disappear.
This technique gives you a little more control over the preview window. But,
because you don’t have an object reference to the preview itself, you have very
little scope for customising it.
VFP 9.0’s alternative preview window
VFP 9.0’s default preview window suffers from the same limitations as in
earlier versions (apart from a couple of minor improvements, such as the
increased number of zoom levels). But did you know that it’s now possible to
invoke an alternative window that overcomes some of those earlier problems?
The alternative window is based on a report listener. But you don’t need to
know anything about report listeners to take advantage of it. In fact, you only
need to make one small change to your code. Instead of this:
REPORT FORM MyReport PREVIEW
REPORT FORM MyReport OBJECT TYPE 1
Figure 2 shows the result.
The new preview window is broadly similar to the old version, but with these
- More zoom levels, including a whole-page
option. (A very minor issue is that the zoom menu appears in ascending
order, which is the opposite of the normal Windows behaviour.)
- A context menu is available, as an alternative
to the toolbar.
- You can choose to view one, two or four pages
at a time (subject to the zoom level).
- Best of all, you don’t see the irritating
change of zoom level when you click in the preview.
As before, the preview is modal by default. But, as before, you can use
NOWAIT to make it modeless.
If you have many REPORT FORM commands scattered around your application, you
won’t need to modify each one separately. Just execute this command near the
SET REPORTBEHAVIOR 90
Once you’ve done that, all REPORT FORM commands containing the old PREVIEW
clause will now invoke the new preview window. (SET REPORTBEHAVIOR is not scoped
to the current data session.)
Going further with the report listener
Because this alternative preview window is based on a report listener, you
can do a certain amount of customisation just by adjusting the listener’s
properties. Consider the following code:
LOCAL loPreview loPreview = NULL DO (_REPORTPREVIEW) WITH loPreview
The _REPORTPREVIEW system variable points to a report previewing application.
By default, that application is ReportPreview.APP. Given enough time and
know-how, you could create your own report previewing application to use in
place of ReportPreview.APP. We’ll discuss that possibility later in the article.
For now, let’s keep things simple.
The third line in the above code calls ReportPreview.APP (or any replacement
for it), passing a NULL object parameter by reference. ReportPreview.APP’s job
is to create a container object that will hold the preview. It uses the
parameter to return a reference to the container.
Having obtained the reference (loPreview in this example), you can access the
container’s properties, for example:
loPreview.CanvasCount = 2 loPreview.ZoomLevel = 4 && 75% loPreview.Width = 800 loPreview.ToolbarIsVisible = .F.
Here, we’re setting the initial canvas count (the number of pages displayed
at one time) to two, the initial zoom level to 75% (the fourth item on the zoom
menu) and the width of the preview to 800 pixels; we are also hiding the
At this stage, there’s nothing visible on the screen. In fact, the report
hasn’t even been rendered yet. So the next step is to instantiate a report
listener object and to point it to our preview container:
loListener = CREATEOBJECT("ReportListener") loListener.PreviewContainer = loPreview lolistener.ListenerType = 1
We’re using the built-in ReportListener class here, but we could just as well
have used a subclass of it. Many developers prefer to use the _ReportListener
foundation class (note the underscore at the start of the name), which offers a
number of additional features.
Setting the listener’s ListenerType property to 1 is important. This tells
the listener to render the pages and to pass them to the preview object. If you
left this property at its default setting of -1, the listener would produce no
The final step is to run the report, specifying the report listener as the
REPORT FORM MyReport OBJECT loListener
The end product is basically the same preview window that we saw earlier
(Figure 2), but subject to whatever changes you made to the relevant property
settings (CanvasCount, ZoomLevel, etc. in this example). You can use this
technique to customise the preview in many useful ways.
Your own preview window
Going further, it’s possible to create your own preview window, with whatever
look and feel you care to give it. Essentially, this involves creating your own
container, that is, the object that’s instantiated by ReportPreview.APP. The
container (which is most often a form) has to meet the requirements documented
in the VFP 9.0 Help topic, The Preview Container API. Remember, it is
this container that will actually hold the preview.
Once you’ve created the container, you must establish an object reference to
it. One way to do that would be to create a substitute version of
ReportPreview.APP. This program’s main job is to instantiate the preview
container. It must receive a NULL object reference as a parameter, and use it to
return a reference to the object it instantiates. With this approach, you don’t
have to change any of the reporting code in your application. You just have to
make sure that _REPORTPREVIEW points to your substitute ReportPreview.APP.
Alternatively, you could simply instantiate the container class directly,
using CREATEOBJECT() or NEWOBJECT(). You then point the listener’s
PreviewContainer property to it, and invoke the report:
loPreview = CREATEOBJECT("MyContainer") loListener = CREATEOBJECT("ReportListener") loListener.PreviewContainer = loPreview REPORT FORM MyReport OBJECT loListener
So how do you go about developing the container class? Unfortunately, that’s
a complex subject, and one that’s beyond the scope of this article. However, we
can point you to a shortcut. The built-in report preview container (the one that
produces the output shown in Figure 2) is written in VFP – and the source is
available. Although you’re not allowed to distribute the source code itself, you
are free to adapt it for your own compiled applications.
To do so, first unzip the XSource.Zip file, which is in the Tools\XSource
folder below the VFP9 folder. The source code for the preview window will be in
the ReportPreview sub-folder. Although there’s no documentation for this code,
it’s reasonably easy to follow. The key component which you’ll want to
investigate is the FRXPreviewForm class, in FRXPreview.VCX (Figure 3).
As you will see, this class contains all the methods for rendering,
navigating, and generally managing the preview. For example, there are methods
called ActionGoFirst, ActionPrint, ActionSetCanvasCount and ActionSetZoom, all
of which do what their names suggest. You can use this code as the basis for
your own customised report viewer, which you can then embellish in whatever way
suits your application.
Figure 4 shows our own generic preview form. This contains code from the
class mentioned above as well as a little custom code of our own. Our main aim
was to place all the required controls – page navigation, zoom, canvas count,
etc. – on the form itself, and thus avoid the user having to rely on the context
menu or toolbar. The preview container is in fact the scrolling region that
occupies the main part of the form. To create that scrolling region, we used the
techniques described in the FoxStuff article, Create a
scrolling region within a form . (A significant drawback of that technique is
that it will only work if the form is modeless.)
Because most of the code in the form is Microsoft’s copyright, we can’t make
the form available for you to download, nor can we show you the code. However,
by using the existing source code as a starting point, you should be able to
create your own preview form in much the same way that we have done.
The third-party option
If all this sounds like too much trouble, you have another option – one that
involves very little programming. There are at least two third-party products
available for purchase that you can use to easily create a custom report viewer.
- FRX2ANY, from Semurg
- XFRX, from Eqeus
We don’t have any recent experience of FRX2ANY, but we have used XFRX on a
recent project, with satisfactory results. Figure 5 shows the report viewer that
we created with the help of XFRX.
This form is similar to the preview window shown in Figure 4, but with some
additional features. These include a Find button that lets the user search for
any text anywhere in the report. With a large report, the search will be slow,
but nevertheless this is a feature that users greatly appreciate. There are also
buttons for exporting the report to PDF or Microsoft Word format. The search and
export features are both provided by XFRX, and require very little additional
programming. Although not shown here, XFRX also lets you create hyperlinks and
bookmarks, and it supports many additional export formats.
We hope that this article has demonstrated that you don’t need to put up with
the drawbacks of Visual FoxPro’s built-in preview window. Whether you tweak the
built-in window, create your own viewer, or use a third-party product, you’ll
end up with a better way of showing your reports on the screen – something your
users are sure to thank you for.
Mike Lewis Consultants Ltd. December 2007.
More Visual FoxPro articles | Crystal Reports articles |
Recommended books | Visual FoxPro consultancy |
FoxStuff is maintained by Mike Lewis Consultants Ltd. as a service to the
VFP community. Feel free to download and use any code or components, and to pass around copies of the
articles (but please do not remove our copyright notices or disclaimers).
The information given on this site has been carefully checked and is believed to be correct,
but no legal liability can be accepted for its use. Do not use code, components or techniques
unless you are satisfied that they will work correctly in your applications.
© Copyright Mike Lewis Consultants Ltd.