|
|||||||
|
|
![]() |
|
|
|
|
||
|
Build Better Forms by Drawing Dynamic Boxes by Michael Sansoterra [The code for this article is available for download.] When people think of printing invoices or purchase orders on the iSeries, they often think in terms of expensive forms software or graphic overlays. These fancy techniques are often used to create a form on which individual fields are to be boxed in. But an often-overlooked DDS keyword allows you to make boxes on your printer files with no special gimmicks. It also enables a programmer to do something overlays can't do. This special DDS keyword is BOX. BOX allows a programmer to draw boxes in an externally described printer file. BOX has five required parameters: first-corner-down, first-corner-across, diagonal-corner-down, diagonal-corner-across, and line-width. The first two parameters specify the coordinates of the box's upper right hand corner. The next two specify the lower right hand corner. The last parameter specifies the thickness of the line to be drawn. The coordinates are specified in the printer file's unit of measure (UOM). Starting with OS/400 V5R1, there are two more optional parameters: color value and shading. Therefore, assuming your printer file uses inches as its UOM, drawing a box in the upper left hand side of the page that is two inches wide and two inches high is as simple as coding this: A R RCDBOX A BOX(0 0 2 2 *MEDIUM) While drawing predefined box sizes is nice, this keyword offers additional versatility. Instead of hard-coding coordinate values in the box, you can also specify variable names.
* SHOW BOX
*
A R RCDBOX
A TEXT('DISPLAY BOX OUTLINE')
A BOX(&UYC &UXC &LYC &LXC *NARROW)
A UYC 5S 3P TEXT('BOX UPPER Y COORDINATE')
A UXC 5S 3P TEXT('BOX UPPER X COORDINATE')
A LYC 5S 3P TEXT('BOX LOWER Y COORDINATE')
A LXC 5S 3P TEXT('BOX LOWER X COORDINATE')
Now you can do something that a static overlay will not let you do: You can draw boxes on the fly to fit your needs. For example, some forms may require boxes to separate groups of items in the detail section of an invoice. However, the number of lines in the section will never remain constant, so the box size will always adjust accordingly. With a simple RPG subprocedure to control the coordinates, you can create code to draw boxes any size you want:
*----------------------------------------------------
* Write Box Based on Column Coordinates
*----------------------------------------------------
p WriteBox b
*
d WriteBox pi
d UYCoord 3 0 value
d UXCoord 3 0 value
d LYCoord 3 0 value
d LXCoord 3 0 value
*
* The printer file attributes are: 6LPI, 10CPI
* Convert unit for single character
* (1 LINE / 6 LPI = .166667 in)
*
d cLHeight c .1666666667
d cLWidth c .1
*
d cDftYMargin c .0
d cDftXMargin c .0
/Free
//
// Convert columns to unit of measure (inches)
//
UYC=(UYCoord-1) * cLHeight + cDftYMargin;
UXC=(UXCoord-1) * cLWidth + cDftXMargin;
LYC=(LYCoord) * cLHeight + cDftYMargin;
LXC=(LXCoord) * cLWidth + cDftXMargin;
//
// Draw Box at specified UOM coordinates
//
Write rcdBox;
Return;
/End-Free
P WriteBox e
To make it easy to work around fixed position characters, this subprocedure accepts column coordinates and converts them to the unit of measure required by the BOX keyword. Therefore, if you want a box that starts with its upper left hand corner at coordinate 1,1 of the page, and you want it to end at coordinate 10,80, simply specify CallP WriteBox(1:1:10:80). Notice that the coordinate conversion from columns to UOM requires the subprocedure to know the character per inch (CPI), lines per inch (LPI), and default margin settings used by the printer file. For simplicity I have hard-coded these values. WriteBox can be made more versatile by passing the LPI, CPI, and margin offset values as parameters. To draw boxes on the fly in your code, follow these steps. First, print your data, counting how many lines or columns you've used. Next, calculate upper and lower coordinates of the box to fit around your data. Then draw the box with WriteBox. Click here to download the source for a printer file and for RPG and COBOL programs that demonstrates how WriteBox is used. (Thanks to Mary Sickler for the COBOL version.) Be sure to compile the printer file with the options specified in the header. The DEVTYPE parameter for a printer file using the BOX keyword must be *AFPDS; otherwise the BOX keyword will be ignored. You can send an *AFPDS spool file to an AFPDS-enabled printer and also a network-connected ASCII printer, as long as the printer device's (or remote output queue's) host print transform option (TRANSFORM) is set to *YES, along with the proper manufacturer and model specified (MFRTYPMDL). In general, the host print transform option should work with all printers that understand Printer Control Language (PCL) or Printer Job Language (PJL) print streams. To send an *AFPDS spool file to an *IPDS printer, you need the PSF/400 product installed. Troubleshooting If your results don't look right, remember WriteBox uses column coordinates. For the starting coordinates, WriteBox draws at the left of the column and at the top of the row. For the ending coordinates, WriteBox draws at the right of the column and at the bottom of the row. An easy mistake is to allow the boxes to slightly overlap by specifying something like this: // Draw two boxes side by side CallP WriteBox(3:1:10:20) // Incorrect code CallP WriteBox(3:20:10:40) // Boxes will overlap To draw two boxes next to each other, you must start the upper coordinate of the second box starting in column 21 rather than column 20: // Draw two boxes side by side CallP WriteBox(3:1:10:20) // Correct code CallP WriteBox(3:21:10:40) // Boxes are side by side If you still think you've coded your boxes correctly, use Operations Navigator to view your spool files. If your boxes look incorrect in the OpsNav viewer, there's probably a problem with the way you're using WriteBox. Control Your Print Files! Many programmers don't bother setting the attributes of their printer files and, instead, let the iSeries decide how to rotate the page and what the best-size font should be. To avoid problems with WriteBox, make sure that you specify all of the necessary page rotation and CPI and LPI settings when you create your printer file. These values should be consistent between the printer file and the WriteBox subprocedure. Allowing the iSeries to decide these print file attribute values for you is asking for incorrect output. Build Them Boxes Click here to see an example of what WriteBox can do. The detail boxes on the page dynamically grow vertically, depending on the amount of data in the section. Subsequent boxes are drawn with a starting coordinate that depends on the size of the prior box. (I removed the data from the image of the report with the Paint application, so as not to reveal private information about the client I wrote this for.) Building dynamically sized boxes at runtime can greatly enhance your forms printing without the cost of additional software. Make your forms snazzy now! Additional notes on the BOX keyword taken from the IBM DDS Reference manual:
Michael Sansoterra is a programmer/analyst for SilverLake Resources, an IT services firm based in Grand Rapids, Michigan. E-mail: msansoterra@silver-lake.com
|
Editors
Contact the Editors |
| Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved. |