v1.10 |
509 Center Bay City, Michigan Sales (989) 892-9242             Support (989) 686-8860 |
A very powerful feature of Visual PL/B is the PRINT PAGE instruction. This instruction works very much like a DISPLAY to allow you to format a printed page randomly then print the entire page at one time.
TOPICS:
- Defining the printer object
- PRTOPEN to get the printer going
- PRTOPEN CANCEL button and how to detect it.
- PAGESETUP alternate (maybe better) way to open a printer.
- PRTCLOSE send your report to the printer.
- PRTPAGE, the actual printing mechanism.
- GETFILE to recover information about the printer.
- GETINFO to recover information about the printer.
- Printer management issues
- GETINFO TYPE=font to get a print string width (see MMCCJUST).
- Tips and techniques
- *Ph:v Positioning on the page
- *UNITS controlling the spacing on a page
- *PICT printing a picture
- PRTSCRN Printing a SCREEN image
- COLORS for foreground / background
- PL/B NOTEBOOK INDEX
DEFINING THE PRINTERPrinter files are definded using the PFILE instruction. This is anologous to the FILE, IFILE and AFILE definitions for disk files. You'll open and close the printer file, much like a disk file.PRTOPEN STATEMENT
Here is how we usually define a printer object (or file). Note that we also set up a couple of our own work areas.PRINTER_FILE PFILE ;you MUST define the printer PRINTER_NAME DIM 31 ;we use this for optional name SPOOL_ERROR DIM 1 ;this is our own error flagBefore using the printer it must be opened with the PRTOPEN statement.PRTOPEN: CANCEL button
There are a number of parameters that you can use with the PRTOPEN. The minimum statement is:PRTOPEN {pfile name}, {windows printer name}, {job name}The windows printer name and the job name can both be null strings, but you must have SOMETHING in those positions. It can be a literal or a string variable name. For example you could code:PRINTER_FILE PFILE PRTOPEN PRINTER_FILE, "", ""You could also code it like this:PRTOPEN PRINTER_FILE, "HP Laserjet 4", ""Or code it like this:PRTOPEN PRINTER_FILE, PRINTER_NAME, ""The printer name is very significant. If the name is a null string, or a null literal, then the windows printer selection dialog box will open and the user can select the printer.
The printer name string can also contain the name of an active and valid printer on the computer. If you do this, you have to be sure that you use a valid name of a printer that's actually installed on the computer where the program is running.
The generally accepted method is to leave the printer string NULL. This let's the user select the printer at run time.
In summary, the data in the windows printer name does these things:
- "-" Tells the system to use the currently selected printer. (see PAGESETUP below).
- "@" or "@printer name" or Does a "print preview" after you do a PRTCLOSE.
- "@?" or "@?printer name" or You can tell the system to do a print preview, AFTER the print selection dialog, upon the PRTCLOSE
- Of course you can also explicitly name the printer.
The standard Windows printer selection dialog includes a cancel button. If the user clicks that it will cause a runtime error unless you trap for it. The Sunbelt manual says you get an S22 but experience has shown that you actually get an S10. (At one time we had a note that you get an S18... can't prove that now.)PAGESETUP STATEMENT
The trap to use for this is "SPOOL". Here's how we handled it:MOVE NO,SPOOL_ERROR ;this will be our flag TRAP PRINTER_ERROR IF SPOOL ;watch for an error PRTOPEN PRINTER_FILE, "", "" ;let user specify printer TRAPCLR SPOOL ;clear the trap if not taken . IF (SPOOL_ERROR != NO) ;see if there was an error ..... could do something ... RETURN ;in our case we return ENDIF ..... more program.... . printer_error ;routine for the TRAP MOVE YES,SPOOL_ERROR ;just note error RETURN ;S$ERROR$ would have full dataThe PAGESETUP statement provides another method for controlling the PRTOPENPRTCLOSE STATEMENT
Normally the PRTOPEN with a null printer name will cause the Windows printer dialog to open, thus allowing the user to select the printer.
When you already KNOW the printer name, you can just provide it in the PRTOPEN and skip the dialog.
Sometimes the second open of the printer causes strange problems. For example, we've seen examples where the second PRTOPEN leaves Windows not knowing what type of printer is selected. After that, things like setting landscape orientation on a laser just won't work.
PAGESETUP selects a printer, and remembers what that printer is, without actually doing an open to the printer. Later you can do as many PRTOPENs as you want using the printer defined by the PAGESETUP.
We don't know where the PAGESETUP information is stored. One way to think about is that PAGESETUP puts the printer information onto the clipboard and PRTOPEN uses whatever is stored there.
PAGESETUP has no parameters. It's a standalone statement.
PAGESETUP opens the printer selection dialog on the options side, not on the printer selection side where you normally land. The user can set options, but your program can override them with "*" parameters in the PRTPAGE instruction.
Here's an example:Suppose you want to provide a button for printing envelopes when the user selects a customer from a DATALIST.
On the button click you'd retreive the customer information then CALL a routine that does something like this:envelope_routine IF (FIRST_TIME = YES) MOVE NO,FIRST_TIME PAGESETUP ENDIF PRTOPEN PRINTER_FILE, "-", "" ... do the envelope print.... PRTCLOSE PRINTER_FILE RETURN
The first time the routine is called, it does the PAGESETUP which establishes the printer. This only happens once.
Each time the routine is called it will open the printer file using the "-" printer name parameter which say to use the currently defined printer. The envelope is printed and the printer is closed which causes it to print immediately.
The user selects the printer only once then just gets an envelope each time the button is clicked.Once a printer is opened, all output is sent to the Windows print handler. Nothing prints until you close the print file with PRTCLOSE. The format is simply:PRTPAGE (print) STATEMENTSPRTCLOSE PRINTER_FILE ;close the printerYou can have multiple printer files open at any time. They can be opened and closed independently.
In the envelope example above, you could open a summary report printer file when the job starts and you'd print a single line to that report each time an envelope is printed.
The envelopes would print one at a time, with their printer file opening and closing each time.
At the end of the run, you'd close the summary report and it would produce a list of all the envelopes which had been printed.
The summary report job would be a good example of a place to use the "@" printer name option in the PRTOPEN. That option tells the printer select dialog to open after the CLOSE, not after the OPEN. It delays the printer selection to the END of the run.The PRTPAGE instruction is a cross between a DISPLAY and a traditional PRINT instruction. Many of the list instructions are common to one format or the other. There is also a resemblence to a file I/O instruction in that you must name the printer. (You could have multiple printers open at the same time!)
To illustrate the similarity to a PRINT statement, note that you can code something like this:PRTPAGE PRINTER_FILE;"This is data": *N,"Here's the next line": *FThat prints two lines and "formfeeds" to the next page. Note that, like a file I/O routine, the printer file is named at the beginning and is followed by a semi-colon.
To illustrate how the page print is similar to a DISPLAY statement consider this example:PRTPAGE PRINTER_FILE;*P10:10,*BOLDON,"position 10, line 10": *BOLDOFF: *P01:01,"back to top of page": *P50:20,"farther down page"There are numerous other commands including line and box drawing, font control, line control and the like.
GetFILE for printersGETFILE {printer file}, PRTNAME=Printer_fullname, HDC=Printer_Handle, etc.
For most cases, you would use GETINFO for printers. It gives the most information. One drawback is that it does not provide the full printer name. GETINFO gives just the first 31 bytes of the printer name. Many printers have much longer names!
GETFILE is supposed to give the full printer name. This requires PL/B version 9.x and above. Before that you still got the 31 byte name
GetINFO for printersThe GETINFO instruction can be used to retreive a lot of information about printers. There are several variations:GETINFO PRINTERS,{string} returns the DEFAULT printer name string. It doesn't matter what printer you have opened, this is the current DEFAULT printer name.
- GETINFO PRINTERS,{string} (gets default printer name)
- GETINFO PRINTERS,{datalist} (gets list of all printers)
- GETINFO TYPE={printer object}, {string} (gets open printer specs)
Note that the printer name which is returned may be more than you want, need or can use. For example you may get:
HP LaserJet 4,HPPCL5MS,\\Gateway\1
If that occurrs, you want only the bytes up to the first comma:
HP LaserJet 4
See special note in printer management section dealing with network printers and printer name lengths.
GETINFO PRINTERS,{datalist} populates the {datalist} with a list of all the printers defined on the computer. This allows you to do your own printer selection dialog without actually opening a printer file.
Unlike the default printer format shown above, this format gives you only the printer name. You can use that name directly.
GETINFO TYPE={printer object}, {string} returns a predefined string defining the currently opened printer and just about everything about it.
The layout of the returned string is defined in the on-line help. We cut that table and pasted it into a file which we INCLUDE in our programs when we need the information. You can cut the table from this page if you want it. (Our include file is Z:PRT-INFO.PLS.)
WHERE in the on-line PL/B manual from Sunbelt? Go to the GETINFO index entry and click it. Then look for "PFILE Information" in the topic list. Click on it. You get:................................................... . This was extracted from the Sunbelt ON-LINE MANUAL 12/6/2000. . That was PLBWIN version 8.4 . . The GETINFO instruction retrieves the following information . when the TYPE keyword specifies a PFILE: . . For example: . GETINFO TYPE={printer file}, PRINTER_INFO_DATA . . 1.0 millimeter = 0.039370078740157 inches . 25.4 millimeters = 1 inch . . Column Size Value . 1 8 Current Printer Driver version . 9 8 Page width in pixels . 17 8 Page height in pixels . 25 8 Page width in millimeters . 33 8 Page height in millimeters . 41 8 Number of color bits per pixel . 49 8 Number of device specific fonts . 57 1 Can Print Pictures ? (Y or N) . 58 4 User specified copies specified by user (future) . 62 1 Print All Pages (Y or N) . 63 1 Print Selection Only (Y or N) . 64 8 Print dialog start page value . . 72 8 Print dialog end page value . 80 1 Print Alignment Right (Y or N) . 81 1 Print Alignment Decimal (Y or ) . 82 1 Fill On Enabled (Y or N) . 83 1 Pict Rectangle Enabled (Y or N) . 84 1 Overlay Enabled (Y or N) . 85 4 Number of characters in Printer Name . 89 31 Printer name . 120 10 Print orientation as follows . 1 = Portrait . 2 = Landscape . . 130 10 Paper size as follows: . 1 = Letter, 8 1/2- by 11-inch . 2 = Letter Small, 8 1/2- by 11-inch . 3 = Tabloid, 11- by 17-inch . 4 = Ledger, 17- by 11-inch . 5 = Legal, 8 1/2- by 14-inch . 6 = Statement, 5 1/2- by 8 1/2-inch . 7 = Executive, 7 1/4- by 10 1/2-inch . 8 = A3 sheet, 297- by 420-mm . 9 = A4 Sheet, 210- by 297-mm . 10 = A4 small sheet, 210- by 297-mm . 11 = A5 sheet, 148- by 210-mm . 12 = B4 sheet, 250- by 354-mm . 13 = B5 sheet, 182- by 257-mm . 14 = Folio, 8 1/2- by 13-inch . 15 = Quarto, 215- by 275-mm . 16 = 10- by 14-inch . 17 = 11- by 17-inch . 18 = Note, 8 1/2- by 11-inch . 19 = #9 Envelope, 3 7/8- by 8 7/8-inch . 20 = #10 Envelope, 4 1/8- by 9 1/2-inch . 21 = #11 Envelope, 4 1/2- by 10 3/8-inch . 22 = #12 Envelope, 4 3/4- by 11-inch . 23 = #14 Envelope, 5- by 11 1/2-inch . 24 = C Sheet, 17- by 22-inch . 25 = D Sheet, 22- by 34-inch . 26 = E Sheet, 34- by 44-inch . 27 = DL Envelope, 110- by 220-mm . 28 = C5 Envelope, 162- by 229-mm . 29 = C3 Envelope, 324- by 458-mm . 30 = C4 Envelope, 229- by 324-mm . 31 = C6 Envelope, 114- by 162-mm . 32 = C65 Envelope, 114- by 229-mm . 33 = B4 Envelope, 250- by 353-mm . 34 = B5 Envelope, 176- by 250-mm . 35 = B6 Envelope, 176- by 125-mm . 36 = Italy Envelope, 110- by 230-mm . 37 = Monarch Envelope, 3 7/8- by 7 1/2-inch . 38 = 6 3/4 Envelope, 3 5/8- by 6 1/2-inch . 39 = US Standard Fanfold, 14 7/8- by 11-inch . 40 = German Standard Fanfold, 8 1/2- by 12-inch . 41 = German Legal Fanfold, 8 1/2 by 13-inch . 256= Custom user defined . . 140 10 Custom paper length in 10ths of mm . 150 10 Custom paper width in 10ths of mm . 160 10 Printed output scaling factor . 170 10 Num of copies printed if multi-page copies supported . 180 10 Paper feed source as follows: . 1 = Upper tray or only one . 2 = Lower tray . 3 = Middle tray . 4 = Manual . 5 = Envelope . 6 = Envelope Manual . 7 = Auto . 8 = Tractor feed . 9 = Small FMT . 10 = Large FMT . 11 = Large Capacity . 14 = Cassette . 15 = Form source . . 190 10 Print quality as follows: . -1 = Draft . -2 = Low . -3 = Medium . -4 = High . nnn = Dots per inch when positive . . 200 10 Color usage as follows: . 1 = Monochrome . 2 = Color . . 210 10 Type of double sided print as follows: . 1 = Simplex . 2 = Vertical . 3 = Horizontal . . 220 10 Copies being collated as follows . 0 = No . 1 = Yes . 230 8 Current vertical print position . 238 8 Current horizontal print position . .................................. . INCH_PER_MM FORM "0.03937" ;conversion factor for MM to inches . 0.039370078740157 = full factor PID_PG_I_WIDE FORM 8.8 ;use for conversions PID_PG_I_HIGH FORM 8.8 ;use for conversions . PRINTER_INFO_DATA LIST PID_DRV_VER DIM 8 Current Printer Driver version . PID_PG_P_WIDE DIM 8 Page width in pixels PID_PG_P_HIGH DIM 8 Page height in pixels PID_PG_M_WIDE DIM 8 Page width in millimeters PID_PG_M_HIGH DIM 8 Page height in millimeters . PID_COLOR_BITS DIM 8 Number of color bits per pixel PID_NUM_OF_FONTS DIM 8 Number of device specific fonts PID_PIC_OK DIM 1 Can Print Pictures ? (Y or N) PID_USER_COPIES DIM 4 Copies specified by user (future) PID_PRINT_ALL DIM 1 Print All Pages (Y or N) PID_PRINT_SEL DIM 1 Print Selection Only (Y or N) . PID_START_PAGE DIM 8 Print dialog start page value PID_END_PAGE DIM 8 Print dialog end page value PID_ALIGN_RIGHT DIM 1 Print Alignment Right (Y or N) PID_ALIGN_DEC DIM 1 Print Alignment Decimal (Y or ) PID_FILL_ON DIM 1 Fill On Enabled (Y or N) PID_PICT_RECT DIM 1 Pict Rectangle Enabled (Y or N) PID_OVERLAY DIM 1 Overlay Enabled (Y or N) . PID_NAME_SIZE DIM 4 Number of characters in Printer Name PID_NAME DIM 31 Printer name . PID_ORIENTATION DIM 10 Print orientation CODE PID_PAPER_SIZE DIM 10 Paper size CODE . PID_PGLEN_MM DIM 10 Custom paper length in 10ths of mm PID_PGWIDTH_MM DIM 10 Custom paper width in 10ths of mm PID_SCALING DIM 10 Printed output scaling factor PID_COPIES DIM 10 Copies printed if multi-page copies supported PID_FEED_SOURCE DIM 10 Paper feed source CODE PID_QUALITY DIM 10 Print quality CODE PID_COLOR_USAGE DIM 10 Color usage CODE . PID_DOUBLE_SIDE DIM 10 Type of double sided print CODE PID_COPYCOLLATE DIM 10 Copies being collated CODE PID_V_POS DIM 8 Current vertical print position PID_H_POS DIM 8 Current horizontal print position LISTEND
Printer Management IssuesThere are a number of things to keep in mind with printers. I'll note some here as they come up.
- Short printer names:
The first time we open a printer in a session, the printer name is nul. Just as when you open a data file with a nul name, you get the open dialog to allow the user to select the file or, in this case, the printer.
When the printer opens, we use GETINFO to get the printer's name and we keep that in memory.
If we need to open the printer again in the same session, we use the printer name we saved. The printer opens without the dialog and life goes on.
The problem is that GETINFO returns only the first 31 bytes of the name. If people use a longer printer name, the program may bomb or may just act like the user canceled the printer open dialog.
Many printers these days are installed with long names. Things like:
HP Laserjet 4000 extended edition in a beige case on QuadBC01
GETINFO cuts that off at 31 bytes!
GETFILE is supposed to allow you to get the full printer name. Prior to PLBWIN 9.x it still gave the 31 byte name.
There are notes on this in the GETINFO and GETFILE sections above.
- Win XP and the "on" condition:
We ran into a problem where the printer name was something like:
HP LJ 4000 on Quadbc-01
If we tried to open the printer with that name it just would not work.
Matthew knew about it and said that the word "on" in lower case in a printer name has some special meaning to Win XP. Change the "on" to some upper case variation and it should work.
We found that Windows will not allow you to put the upper case in the printer name in the printer's properties. You can do it and Windows will put it right back to lower case.
The solution is to do this programmatically:SCAN " on ", PRINTER_NAME IF EQUAL SPLICE " ON ", PRINTER_NAME, 4 RESET PRINTER_NAME ENDIF PRTOPEN PRINTER_FILE,PRINTER_NAME....
GETINFO type=font for printers (use for justifying print lines)This instruction allows you to get all the information that you need to justify print lines. It returns the width in pixels for any line when given the FONT and the PRINTER.
MMCC has a generalized loadmod called MMCCJUST which will do all of this for you. Give it the string, font and printer and it will return a table of lines to fit the width that you define. (In the UTIL-PLB folder.)
GETINFO TYPE={font object}, {string}, PRINTER={printer object} returns a predefined string defining information about the string as it would apply if tinted on the named printer object.
The fields for this info string are defined in the COMMONWK.PLS include unit..... . You can get this with: 4/04/2001 . MOVE INPUT_DATA, STRING . GETINFO TYPE={font},STRING,PRINTER_FILE . UNPACK STRING, FONT_INFO . . The GETINFO will read the contents of STRING based on . the FONT OBJECT and return, in STRING, the following . string of information: . FONT_INFO LIST FI_ASCENT FORM 4 Pixels above baseline for a character FI_DESCENT FORM 4 Pixels below baseline for a character FI_HEIGHT FORM 4 Height of a character (ascent + descent) FI_FULLHEIGHT FORM 4 Full height character (height + external L/S) FI_AVG_CHAR FORM 4 Average character width - generally letter "X" FI_MAX_CHAR FORM 4 Maximum character width - wides in font FI_FONT_S_W FORM 4 Font string width truncated to 4 bytes FI_FIRST_CHAR DIM 1 First character in the font FI_LAST_CHAR DIM 1 Last character in the font FI_PIXELS FORM 8 Last character in the font LISTEND
ONE FORM "1" Just a constant "1" PAGENUM FORM 3 Page number MAXLINES FORM "55" Max lines we can get on a page LINECNT FORM " 1" Line we're at on the page LH FORM 5 Calculated HORIZONTAL position LV FORM 5 Calculated VERTICAL position LINE_HEIGHT FORM "10" Height in 1/100th inches . print_data CALC LV = LINECNT * LINE_HEIGHT CALC LH = 10 PRTPAGE PRINTER_FILE;*UNITS=*LOENGLISH: *PLH:LV,"Here is the data" CALL LINECHEK RETURN . ............................... . Central page overflow tester . Count the line just printed and see if room for more. . linechek ADD ONE,LINECNT IF (LINECNT < MAXLINES) RETURN ENDIF . pagehead ADD ONE,PAGENUM MOVE ONE,LINECNT . PRTPAGE PRINTER_FILE;*F: "HEADING STUFF": "Page:",PAGENUM ADD FIVE,LINECNT RETURN
Top Margin 15 Line size 12 Middle column 250 Footer position 800
PICT_DEF PICT PICT_NAME DIM 30 MOVE "MMCCLOGO.JPG",PICTURE_NAME CREATE PICTURE_THING=20:60:20:60,PICTURE_NAME PRTPAGE PRINTER_FILE;*P20:10,"HERE IS THE PICTURE": *PICT=21:30:10:20:PICT_DEF;
PRTPAGE PRINTER_FILE;*P20:10,"HERE IS THE PICTURE": *PICTRECT=*OFF: *PICT=21:30:10:20:PICT_DEF;
{window-name}.FormToPict GIVING {pict object}You must define the pict object in your program, but the method will take care of the CREATE for you. Once you have the picture, you print it just like any other picture with any of the controls, and sizing that you want.
FORM_PICTURE PICT F1_Window.FormToPict GIVING FORM_PICTURE PRTPAGE PRINTER_FILE;*P=10:01,"Here's the screen print:": *PICTRECT=*ON: *PICT=02:30:10:100:FORM_PICTURE;
v1.10 |
Send e-mail to MMCC. |