I’ve created another little demo container to show you how to manage the REPORT PREVIEW process. You may think that you have this one sussed already, and wonder why I make such a big deal of it. If you think this, there are two issues you have yet to „meet“ in VFP that are just lurking around the corner.
The first issue concerns text preview (REPORT FORM ASCII). I admit that I don’t quite understand how _ASCIIROWS works, I just know that it helps solve the problem. I’ll quote from the relevant Knowledge Base article (Q141030):
When you increase the value of the _ASCIIROWS system variable, the output of a report to the text file does not look the way you might expect. There are more blank lines in the report. It does not seem that more information is printed on one page if the value of _ASCIIROWS is changed from 63 to 120, but there are more blank lines.
There’s more. I consider this information so strange, and so critical, to text preview in VFP that I’ve included this entire KB article in the source code for this session, under the title ASCII_R.HTM.
The more common issue with report previewing in VFP is the issue of REPORT PREVIEW window control. While we received the ability to use a WINDOW clause on the REPORT PREVIEW command in VFP, the preview is always within _SCREEN (even if the WINDOW-clause window was Desktop, or ShowWindow = 2, or whatever). This behavior is very unfortunate from the point of view of people who write applications based around top forms, who may not even be showing _SCREEN in the rest of their applications.
The way around this problem is torturous, and it’s the main reason I wrote demoPreviewReport. You’ll find this little class in DEV05.VCX, showcased in PREVIEW.SCX in your source code. You can DO FORM Preview, to see its behavior within SCREEN, or you can call a wrapper program TOP_PREV.PRG, to see the Preview screen at work in a top form.
The PREVIEW.SCX form itself is insignificant, although it does provide the most stripped-down and primitive version of a „data-driven“ report dialog I’ve ever written. (The combo box with a list of printers derives its list from an ADIR()! You may have to add some FRXs into it directory, in fact, before you can get it to do anything meaningful.) I’ve deliberately made it a modal form, to showcase one of the problems with previewing and its ShowWindow attribute is 1 (Show In Top Window) so that it can demo both FoxFrame and topform-type behavior.
There are two significant pieces of code in the demoPreviewReport container-class object housed in PREVIEW.SCX. The first one is a method called CheckFrameWindow, which acts at initialization to determine whether the control’s environment is the Fox frame or a top form. Although this code is quite useful, it is not report-specific, and we need not discuss it further here.
The second significant method in demoPreviewReport is DoPreview(), which accepts the name of a report and executes either a text or graphical preview, depending on the state of the radio buttons in the container. Although a number of aspects of this code, such as the check of the radio buttons, is not generic, it accomplishes the two types of preview using code that will solve your top form previewing problems and possibly a few others, as well.
I will list the main issues here, besides the text preview _ASCIIROWS problem already mentioned above, and then reproduce the method in its entirety:
Are we having fun yet ;-)? Here’s a figure to show you one incarnation of PREVIEW.SCX called in „top form mode“ by TOP_PREV.PRG, and then the code:
Is it possible that, underneath this unimpressive screen shot, lies a lot of truly interesting code?? Check out class demoPreviewReport, in DEV05.VCX, to find out!
* demoPreviewReport.DoPreview method
LPARAMETERS tcReport
LOCAL lcWindow
lcWindow = WONTOP()
DEFINE WINDOW winPreview ;
FROM 0,0 TO SROWS(),SCOLS() ;
IN SCREEN ;
SYSTEM FLOAT GROW ZOOM CLOSE ;
TITLE „Report Preview“ NAME winPreview
DO CASE
CASE THIS.cPreviewType == „TEXT“
LOCAL lcFileName, lcClauses
_ASCIICOLS = 80
_ASCIIROWS = 63
lcFileName = „R“+SYS(2015)+“.TXT“
winPreview.FontName = „Courier New“
winPreview.FontSize = 8
IF THIS.lInFoxFrame
lcClauses = „ WINDOW winPreview „
ELSE
lcClauses = „IN MACDESKTOP WINDOW winPreview“
ENDIF
REPORT FORM (tcReport) ASCII ;
TO FILE (lcFileName) NOCONSOLE
MODI COMM (lcFileName) &lcClauses
ERASE (lcFileName) NORECYCLE
IF NOT EMPTY(lcWindow)
ACTIVATE WINDOW (lcWindow) SAME
ENDIF
CASE THIS.cPreviewType == „GRAPHICAL“
* now we deal with top forms and
* the vagaries of runtime in earnest:
#DEFINE WINDOWSTATE_MAXIMIZED 2
IF NOT THIS.lInFoxFrame
LOCAL llScreenWasVisible, ;
llScreenScreenWasMaximized, ;
liScreenHeight, ;
liScreenWidth, ;
llScreenWasAutoCentered, ;
lnScreenTop, lnScreenLeft
llScreenWasAutoCentered = _SCREEN.AutoCenter
llScreenWasVisible = _SCREEN.Visible
llScreenWasMaximized = ;
(_SCREEN.WINDOWSTATE = WINDOWSTATE_MAXIMIZED)
IF NOT m.llScreenWasMaximized
* the following causes too much
* flash because it activates screen,
* _screen.WindowState = n_WINDOWSTATE_MAXIMIZED
m.liScreenHeight = _SCREEN.Height
m.liScreenWidth = _SCREEN.Width
m.lnScreenLeft = _SCREEN.Left
m.lnScreenTop = _SCREEN.Top
_SCREEN.Width = SYSMETRIC(1)
_SCREEN.Height = SYSMETRIC(2)
_SCREEN.Top = 0
_SCREEN.Left = 0
_SCREEN.AutoCenter = .T.
ENDIF
IF NOT m.llScreenWasVisible
_SCREEN.Show()
ENDIF
ENDIF
ZOOM WINDOW winPreview MAX
REPORT FORM (tcReport) ;
PREVIEW WINDOW winPreview && note no NOWAIT!
* the order of the following lines is crucial,
* for preview to occur in runtime
* after the first REPORT PREVIEW when top forms are used
IF NOT EMPTY(lcWindow)
ACTIVATE WINDOW (lcWindow)
ENDIF
IF NOT THIS.lInFoxFrame
IF NOT m.llScreenWasVisible
* using _screen.Visible
* flashes too much...
_SCREEN.Hide()
ENDIF
IF NOT m.llScreenWasMaximized
* see above...
_SCREEN.Width = m.liScreenWidth
_SCREEN.Height = m.liScreenHeight
_SCREEN.Left = m.lnScreenLeft
_SCREEN.Top = m.lnScreenTop
ENDIF
IF NOT m.llScreenWasAutoCentered
_SCREEN.AutoCenter = .F.
ENDIF
ENDIF
* end crucial <g>
OTHERWISE
* browses?
ENDCASE
RELEASE WINDOW winPreview
One more point about the VFP graphical preview: developers often wonder how to make the report preview toolbar available to their users. They would prefer not to have the View menu, which dynamically shows the toolbar options as necessary, on their application menus, but there is no other obvious way to summon the preview toolbar in an application if the user closes this toolbar at any point.
The following code, in your source code as TOOLBAR.PRG, may be attached to a hotkey to allow the user to bring back this toolbar while a REPORT PREVIEW is up. Unfortunately, for this technique, I am fairly sure that you need to be working within _SCREEN—I doubt it will work with top forms. Notice also that you must have issued the command DEFINE POPUP _MVIEW at some point previous to the REPORT PREVIEW command for this to work. You can’t add the DEFINE POPUP _MVIEW command into the following code, which is meant to be executed while the preview window is WONTOP(), and get it to work. Although the _MVIEW popup has to be defined, however, it does not have to be attached to the _MSM_VIEW system pad, and in fact it never has to be visible at all.
To test this code, RELEASE PAD _MSM_VIEW OF _MSYSMENU and RELEASE POPUP _MVIEW to simulate your application’s „base state“. (If you are feeling brave, just SET SYSMENU TO <nothing> and add a second hotkey to SET SYSMENU TO DEFAULT later.) Then hook up the ability to call the toolbar as follows:
DEFINE POPUP _MVIEW && you don’t have
&& worry about its contents
&& or attaching it to a visible menu pad
ON KEY LABEL F4 DO TOOLBAR.PRG
The two lines above would occur before your REPORT PREVIEW line in the application. Now issue the REPORT PREVIEW line and, while the preview is up, close the preview toolbar. Press F4 to get it back!
Here’s the necessary code. It relies on the fact that the system popup _MVIEW automatically creates a report preview toolbar option when necessary. It’s too bad we don’t have direct access to that menu option, but this will do until things change:
* TOOLBAR.PRG
LOCAL zz, xx
zz = 0
FOR xx = 1 TO CNTBAR(„_mview“)
IF „review toolbar“ $ ;
LOWER( PRMBAR(„_mview“,GETBAR(„_mview“,xx)))
EXIT
ENDIF
IF ISALPHA(PRMBAR(„_mview“,GETBAR(„_mview“,xx)))
* skip the separators...
zz = zz + 1
ENDIF
ENDFOR
KEYBOARD REPL(„{dnarrow}“,zz)+“{spacebar}“
ACTI POPUP _mview
RETURN
I hope you’ve gotten at least a few new ideas with which to polish your VFP reporting. Once your reporting techniques are set, you still have to deal with the issues of distributing and packaging your reports. You’ve already seen that reports can be programmatically CREATEd – I created a report programmatically to find out the VFP default printer above. This is a direction that you may want to investigate further, because reports can be created and massaged dynamically at runtime, as Markus Egger does in GENREPOX, to suit very sophisticated application needs.
You should realize that users can also MODIFY REPORT and LABEL under the runtime library (or, as many of us prefer to call it, the Visual FoxPro Virtual Machine ;-)).. Consider creating your reports as templates and copying them out to disk from within the application, so that your users can affect layout without destroying the built-in copies. The copies on disk will also allow you to swap out printer information from the FRX, when and if this is necessary.
Because reports now contain code in the Data Environment methods, there is one important limitation to MODIFYing report during runtime: method code cannot be edited, because it cannot be compiled under runtime. If your users attempt to do so, perhaps with an innocent rightclick on a Data Environment window during a report editing session, they will simply get a „feature not available“ error. (You may want to use an ON KEY LABEL RIGHTMOUSE * command before the MODIFY REPORT command to try to head off this problem.) Except for the code Report Designing at runtime is as available as it has always been in FoxPro.
FoxFire! is absolutely the „last word“ in VFP pure-Fox reporting techniques.
If you find your users want extensive control over report characteristics, consider using FoxFire! from Micromega Systems, Inc (shown in the figure below, contact http://micromegasystems.com/home.html for more information). FoxFire! does all the FRX-runtime editing for you, and give you extensive tools with which to customize English-language querying for your applications, export to various formats, etc. This session is officially about using the REPORT FORM yourself as a developer, and not about bringing in third party tools, but FoxFire! is a Fox-language utility steeped in Fox reporting techniques. You’ll learn a tremendous amount about reporting by using it, as well as cutting your report design and implementation time drastically.
This material (© Lisa Slater Nicholls) has been prepared for the 1997 European Visual FoxPro Developer Conferences.
You will find that this session and my other session (E-HIGH) share a single set of source code files. Because my session topics are related, and to conserve disk space for everybody, I re-used one data table and a few other items to support all the examples for both sessions.
I want to continue to clarify and update my thoughts, and what I can help you learn, about the topic of this paper. You can check my web site for additional updates to both my session papers: http://www.softspoken.co.nz/devcon97.htm. I’ll also try to post answers to some of the questions that invariably come up after the presentations, if there are some of general interest. Since this session in particular will be extremely interactive, there will be questions we can’t consider fully, or that I re-consider after my original answers, and I’ll try to post everything that comes to light.
There will be no links to this page from other pages on my site. This URL will only be available to people who have legitimately learned about it, either by attending my session or by receiving these notes after the conference, or other appropriate distribution. Thank you in advance for not creating any links to this from your own sites.
And thank you also for your continued interest in these topics, and in my work! If you’d like to talk to me about VFP output, please join me on nttp://msnews.microsoft.com (in any of the public.fox groups). The Fox community, in all its variety and with all its discussions, continues to be a great joy in my life.
Best regards,
Lisa Slater Nicholl