![]() |
|
Published 1999-08-31 Printer-friendly version
This column is part of a series in which I illustrate approaches to common reporting situations. To make it easier for you to follow and later review what I cover, I have created a small dictionary (BREAKS.DCT), and the TPS files to go with it (LETTERS.TPS, BREAK1.TPS, and BREAK2.TPS). These files and the application I create for each column are available for download. This month's application file is CMEX2.APP.
I'm using Clarion5 (ABC) to build the example applications, but in most cases, I use the legacy embeds when placing source code in the report procedures because of their more descriptive names.
This month I've built a report that allows the user to print a letter (the body text and recipient are selected at runtime) using letterhead stationary for the first page, and plain stock for the remaining pages. I've elected to do this "one recipient at a time" to accommodate the simplest scenario, in which the user places one letterhead page and several stock pages in the printer's paper bin before printing.
Because all letterhead stationary doesn't extend the preprinted portion the same distance down the page, I'll need a way to allow the user to control how far down on the first page printing will begin. However, I want to start printing at the top of each subsequent page.
First I created a standard ABC report procedure, where I specified the BREAK1 file as the primary file and the LETTERS file as an Other file. I set this procedure up so that the user selects the desired letter text (from the LETTERS file) and then selects the desired recipient (from the BREAK1 file). I also decided to use a simple INI file-based approach to control the distance I need to skip to start printing below the preprinted part of the letterhead stock.
First I went into the report formatter and deleted the
automatically generated Page Header, Page
Footer, and Form bands. I don't need these
bands for this report, and they will only complicate things by
trying to automatically print.
Next I set the width of the report (the Detail Area) to 7½ inches to allow for a ½ inch margin on each side. Then I set the Y-position of the report to ½ inch from the top of the page, and the height to a little over 9½ inches.
Finally, I set the default font for the report to Arial Regular 10pt.
To have this report operate the way I wanted I needed three
detail bands, so I created two additional detail bands. I renamed
the original band from Detail to
SpacerBand, and also gave it a field equate (FEQ)
label of ?SpacerBand. I named the second band
HeaderBand (with the FEQ ?HeaderBand),
and the third band I named Detail
(?DetailBand).
SpacerBand will be blank when printed, and is used
primarily to push the subsequent bands down below the preprinted
part of the letterhead stock. I say primarily, because I
also used it as the "home" of the textbox control containing the
memo (LET:LetterText) from the LETTERS file. Note that
when I populated this control I left it set to default height and
width and didn't concern myself with where on the band I
placed it. This is because this control will be used indirectly to
supply text lines for the letter, but will not actually be printed
(I hide it at runtime). This band was a convenient place to put the
control where it would not be in my way while working with the
other bands and controls.
HeaderBand is used to print the letter
recipient's information from the selected BREAK1 record.
There's no trickery with this band. It's simply made tall
enough to allow for the controls that contain the recipient
information.
DetailBand is used to print the text from the memo
field. However, this is done one text line at a time. This
approach allows me to have the letter automatically flow from one
page to the next, regardless of the number of lines entered into
the memo. After renaming this band, I populated a
STRING control, made it as wide as I wanted each text
line to be, then renamed it ?TextLine. Note that this
is a simple string control, not a FEQ for a variable. Finally, I
changed the text of the string to something that would remind me of
its intended use.
Now let's look over the code that makes this report work. After selecting the desired LETTERS record and recipient (BREAK1), and opening the report, I set up the report with various runtime changes. In the After Opening Report embed I placed the code in Listing 1 (the comments describe what the code is doing):
SETTARGET(REPORT)
! Following FEQs are in the REPORT
! Get the letterhead skip area
IF GETINI('Letter-Standard','SkipForLetterhead','NotFound'|
,'.\CMEX.INI') <> 'NotFound'
! Reduce by report's printable area offset
LHSkip# = INT(GETINI('Letter-Standard','SkipForLetterhead',|
'NotFound','.\CMEX.INI')) - REPORT{PROP:YPOS}
! if result is less than zero set skip height to zero
IF LHSkip# < 0
LHSkip# = 0
END
! Set "spacer" detail height to skip height
! and maxheight to that same height
?SpacerDetail{PROP:HEIGHT} = LHSkip#
?SpacerDetail{PROP:MAXHEIGHT} = LHSkip#
END
! Set textbox width to fixed string length
?LET:LetterText{PROP:WIDTH} = ?TextLine{PROP:WIDTH}
! Ensure the textbox is hidden
?LET:LetterText{PROP:HIDE} = True
! Ensure the textbox is set to DEFAULT height
?LET:LetterText{PROP:NOHEIGHT} = True
! Ensure Detail band set to DEFAULT height
?Detail{PROP:NOHEIGHT} = True
! Ensure string ctl ypos set to zero
! and its height set to same as textbox lines
?TextLine{PROP:YPOS} = 0
?TextLine{PROP:HEIGHT} = ?LET:LetterText{PROP:LINEHEIGHT}
! Reset to default target (ie. window)
SETTARGET
After setting these report characteristics, I used the Embeditor to find the generated print statements and omit them from the compile. I then followed the omitted code with custom code to do the printing in the way I needed it, as shown in Listing 2.
! Omit the generated print statements
! for all bands print behavior.
OMIT('--omit to here--')
PRINT(RPT:SpacerDetail)
PRINT(RPT:HeaderDetail)
PRINT(RPT:detail)
! Start of "After Printing Detail Section"
! [Priority 4000]
!--omit to here--
! Print the "spacer" band to get past letterhead, logo, etc.
PRINT(RPT:SpacerDetail)
! Print the address, salutation, etc.
PRINT(RPT:HeaderDetail)
! Loop thru all lines of the textbox. For each line
! set the string to the next line of the textbox
! and print that line.
LOOP L# = 1 TO REPORT$?LET:LetterText{PROP:LINECOUNT}
REPORT$?TextLine{PROP:TEXT} = |
REPORT$?LET:LetterText{PROP:LINE,L#}
PRINT(RPT:Detail)
END
That's all there is to it! As you can see, there wasn't much to code once I decided what I wanted to do and decided how I would need to approach it.
As I've stated in past articles, the best way to control the report engine is to eliminate any undesirable automatic print engine functionality whenever possible. In this example the key was to not print the memo in a textbox (which is the approach typically used). Instead, I broke the memo down into individually printed lines of text so I would get automatic page overflow as each page is filled.
If you have a particular reporting question or problem that you'de like to see covered in a future column, please email me at lteames@cpcs-inc.com with your request. I can't promise that I'll be able to use every request I receive, but I'll try my best.
Until next month, Happy Reporting!
Download the example application
Larry Teames is an independent software developer, and one of the four founding members of Team TopSpeed. He is also president of Creative PC Solutions, Inc. which markets the popular Clarion 3rd party product Creative Reporting Tools.
Copyright © 1999-2009 by CoveComm Inc. All Rights Reserved. Reproduction in any form without the express written consent of CoveComm Inc., except as described in the subscription agreement, is prohibited.
Clarion Magazine ISSN 1718-9942
One year: $169
(includes all back issues since '99)
Renewals from $119
Two years: $269
Renewals from $219