Although I’ve already declared HTML the winner as a context-neutral format, and although it is incredibly easy to generate and share with other people, RTF format is another reasonable solution to the problems of portable, well-formatted documents.
RTF tags and formatting instructions are not too much more difficult to emit than HTML, and the format is well-understood by many applications. RTF is quite a bit more difficult to understand when you try to read it straight from the file than HTML, but on the other hand it is also capable, at this stage of the standards game, of formatting refinements that HTML cannot match.
Because RTF originates from before the „net-centric“ application development world, like PostScript, you won’t have any trouble finding a way to print your RTF documents when necessary. At the very least, you could print an RTF document with the following command, using the simple WordPad accessory applet that comes with Win 95:
RUN /N2 "<path\wordpad>" /P "<path\filename>"
Notice the double quotes, which we’ll use within Win95 and NT in case the path to the application or the filename contains spaces. If we want to use a macro-expanded VFP expression in this RUN command, we need to make sure that these double quotation mark delimiters are part of the string that Windows „sees“, so we would build the requisite parts of the expression something like this:
m.filename = ["]+m.filename+["]
m.wplocation = ["]+m.wplocation+[" /P ]
RUN /N2 &wplocation &filename
Of course, you can use the ShellExecute technique demonstrated above to ask whatever application on a system currently „owns“ RTF to print it for you. You have to be certain that there is such an application and that it follows the usual practice of accepting a /P switch followed by a filename on the command line, for printing.
In addition, if you know that a particular application is on disk that definitely has the capabilities you need, you can always RUN or automate that program to print for you, overriding the RTF class default on the given machine. This is particularly good practice if you are using more complex formatting in your RTF documents than WordPad or any other possible defaults can handle. (I tested WordPad with some fairly elaborate documents created in Word 97 and saved as RTF. It did pretty well printing the output, but it omitted Word headers and footers and some greyscale shading effects.)
You can also force an FRX to print RTF for you, as long as a suitable server is available. I’ll probably demonstrate this trick in the session, but I don’t think it’s a terribly good idea (and you’ll easily see why). FRXs can deal with compound formats by using general fields, and VFP 5 is more capable of doing this than earlier versions, but FRXs do not host these objects well or „naturally“. There is little justification for forcing VFP to print such a document, especially considering that all VFP doing is calling the same server you can call directly. You end up with the resource hit of the REPORT FORM plus the server.
Beyond programmatic creation of RTF, you may want to allow your users to create rich text interactively. In the figure below, you can see a form (RTF.SCX in your source code) that demonstrates using the MS RichText control for this user action.
* FrmRTF.cmdPrint.Click()
* thanks to jeff@goldencoast.com (Jeff Blunck)
* on the msnews public.fox groups for
* suggesting this way of getting the
* "device context" from within VFP,
* as recommended by The Waite Group,
* _WIN32 Programming API Bible_
DECLARE integer CreateDC ;
IN WIN32API string,string,string,string
DECLARE integer DeleteDC ;
IN WIN32API integer
cPrinter = GETPRINTER()
IF NOT EMPTY(cPrinter)
hDC = createdc('WINSPOOL',cPrinter,'','')
THISFORM.oleRTF.SelPrint(hDC)
=deletedc(hDC)
ENDIF
RETURN
Note that I am using the standard SelPrint method of this ActiveX control, which uses the „device context“ to send output to a particular printer. If we use the easy WordPad method of printing the RTF output, described above, we have to be satisfied with the current Windows default printer. (Don’t expect your VFP SET PRINTER command to affect WordPad!) Many other RTF servers, including Word, would offer us more control of the printer.
We have another way to get the device context of the printer, if we’re willing to use another OCX (the Common File Dialog control) to derive printer information. The code to do so, in the same situation above (where we need the device context to pass to the RTF control’s SelPrint() method), looks like this:
* alternative FrmRTF.cmdPrint.Click()
* to use common file dialog to get device context
* and print the contents of the RTF control
WITH THISFORM
.oleCommonFileDialog.Flags = 0x100
* this flag is required to store HDC
* but I've left everything else at the default in
* this ole control...
.oleCommonFileDialog.ShowPrinter()
.oleRTF.SelPrint(.oleCommonFileDialog.hDC)
ENDWITH
RETURN
The version of RTF.SCX that you have in your source code has a set of radio buttons to let you choose which way you want to get the device context, and its Print button shows both versions of code in its Click method.
Interactive RTF creation within VFP (RTF.SCX) – version on your disk has radio buttons to select printing method, not shown in this screen shot.
Once we have the RTF control available to us, therefore, we can print the RTF contents without direct reference to any outside application in at least two ways (although the control is presumably still using the default RTF server to manage this task). If we don’t need a form, we can still load the RTF control or RTF and common dialog controls on a hidden form for the express purpose of handling the printing task.
The contents of the control, as edited by the user, could store in a memofield or general field at this point, or simply store permanently on disk. You’d use something like the following simple syntax to save the user’s editing:
LOCAL cFile
cFile = GETENV("TEMP")+"\f"+SYS(2015)+".RTF"
THISFORM.oleRTF.SaveFile(cFile,0)
Should you decide to create RTF output, there are a number of public domain RTF-to-HTML converters for those occasions on which you need to show the output in a browser or publish it on a network instead! (Try http://www.sunpack.com/RTF/latest, for a shareware version by Chris Hector, mailto: chris@sunpack.com)
As a final note on using RTF in your applications, there are RTF printer drivers just as there are HTML printer drivers. Potentially, therefore, you could REPORT FORM directly TO PRINT, using the appropriate driver, and get portable, context-neutral output with no more fuss. However, the RTF printer drivers suffer from the same problems as HTML printer drivers: they are not very controllable programmatically, they are limited in the output they can produce, and using them with FRXs limits you to the formatting available directly from the FRX.
PostScript, RTF, and HTML previewing are very easy to achieve. Ghostview is in essence an application that elevates the status of report previewing to the actual report delivery, with printing almost as an afterthought, for occasional use. Browsers for HTML are ubiquitous. You’ve just seen that the RTF control is a design surface and a previewer, in one. But just because these formats have easy previewing solutions, let’s not overlook the fact that „previewing information“ does not necessarily mean „previewing the final output copy“. We have to remember that the format of the information is not the information itself and that sometimes the most appropriate preview has nothing to do with the final outcome.
What about using a standard form to preview report results? You’ve already seen an example of graphical form previewing in the „Year end Bonus“ form figure above. There are many other times when you might want to design a form for use specifically as a „report preview“, even though this form cannot be „printed directly“.
Matt Peirse at Cornerstone provided me with this idea when he told me about a very complex DOS reporting system he was in the process of converting to Windows. The reports have variable numbers of columns. Matt’s DOS system allows the user to generate the text-based report, review the output, and then change the number of columns on the fly. Based on the number of columns, Matt may use landscape or portrait orientation, and he may also break the report rows up into several chunks that go to separate pages if landscape orientation cannot handle the total column number.
Nancy Jacobsen came up with a system like this years ago, for a FoxTalk article she titled „The Report As Wide As A Football Field.“ It’s a special-purpose kind of report format, but it’s also a reporting problem that probably will never go away, because information needs don’t know anything about the limits of printers, or of paper sizes.
When Matt was working on the Windows version, I thought the users might prefer scrolling across unlimited columns in an HTML document, and let the browser worry about what happens with the text that goes across the page. You could add a <font size ="-1"> instruction, to make the fontsize smaller when you had a lot of columns, or perhaps your columns in an HTML table would be allowed to wrap.
But Matt said, „I realized that they didn’t have to preview the report, they had to preview information that would appear in the report, and that looked like the report, but in a format suitable for the screen. So I made a grid without lines for the detail info, and put the header and footer into the form in whatever format necessary. How I print afterwards is not the same mechanism but who cares??“ He was absolutely right, of course. He achieved something like a highly customized Excel spreadsheet, exactly appropriate to his application and the sensibilities of its users, with a minimum of VFP effort.
Just don’t confuse using a form as a preview with „printing the contents of a form“, as this phrase is used in some other development environments. I personally don’t think it makes much sense to „print a form“, unless the form is exactly like a piece of paper (it has no pageframes, or grids, or other elements that transcend the limitations of hard copy). You can capture the contents of a form and send it to the printer or to the Clipboard using Windows API calls (the appropriate function is keybd_event IN Win32API, apparently), or programs like SnagIt or WinCap, and you’ll get a physical representation of the form. But this solution emphasizes the format, not the information, presented in the form.
I’ve also written a small program called PRTSCRN.PRG which takes a container object reference and designs an FRX on-the-fly to provide a physical representation of the members of that container (recursively, of course) and their current values. You can see the results in the figure below, and peruse the semi-interesting PRTSCRN.PRG code in your source code. However, to me this trick is not the point, which should be to provide explainable and clear information, or a logical representation of the form.
DO PRTSCRN WITH THISFORM from the „Print button“... if you really want to...
Just as a previewing form doesn’t have to exactly match the format of the ensuing report form to be useful, a report that issues from a form shouldn’t have to match the format of the screen form to be useful. Match the format of the information to the needs of the moment, the user, and the use to which the information is being put – don’t try to control them beyond that.
This paper has presented a rationale for a certain way of thinking about VFP reporting. It is not practical to present concrete examples of each technique I have suggested as sample code for these notes, but I’ll demonstrate as many of these techniques as time permits in my session. Beyond these specific techniques, you should find many ways to apply the criteria for good reporting described herein. I’ll be looking forward to seeing what you come up with!
This material ((c) 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-OUT) 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 nntp://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 Nicholls