home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Tool Box
/
SIMS_2.iso
/
code
/
print
/
prtprev
/
genprint.txt
< prev
next >
Wrap
Text File
|
1994-04-03
|
19KB
|
539 lines
How to Add Print Preview to Visual Basic Applications [B_VBasic]
ID: Q113236 CREATED: 29-MAR-1994 MODIFIED:
2.00 3.00
Windows
ENDUSER |
--------------------------------------------------------------
The information in this article applies to:
- Standard and Professional Editions of Microsoft Visual Basic
Programming System for Windows, version 2.0 and 3.0
--------------------------------------------------------------
SUMMARY
=======
This article describes how to create printing routines that can
print to the printer or to a picture box. This enables you to add
print preview capabilities to your Visual Basic applications.
There are several ways that you could implement print preview in
your applications. This article describes one method that is easy
to do in Visual Basic and works well.
MORE INFORMATION
================
Generic Printing
----------------
It would be ideal to have a generic print routine that could print
to the printer or to the screen depending on what you pass it. The
Visual Basic printer object and picture box control have many of the
same methods and properties. For example, both of these are valid:
Printer.Print AString
Picture1.Print AString
It would be nice if you could pass a generic object to a subroutine
and the subroutine would use the Print method off of the generic object
as in this example:
Call PrintJob(Printer)
Call PrintJob(Picture1)
Sub PrintJob(GenericObject As Object)
GenericObject.Print AString
End Sub
Unfortunately, this is not possible. The Visual Basic Printer object
is a system object, so it can't be passed as a parameter.
This leaves you with two choices in Visual Basic. You could create two
routines -- one for printing to the printer and one for print preview.
However, the code would not be reusable in your future projects. The
second approach is to write your own set of routines that can print to
the printer or a picture box based on the value of a flag. This is the
method used in the example code given below. Once you create the
routines, you can re-use them in future programs.
The example creates routines that closely mimic Visual Basic's built in
methods and properties. However, you could use this approach to create
high-level routines that greatly simplify your printing needs.
The routines work by checking the variable PrinterFlag. PrinterFlag is
True when printing is going to the printer and False when printing to
the picture box.
Here's the print routine from the example. Notice how it is just a
shell function that determines what to print to and then does it.
Sub PrintPrint (PrintVar)
If PrinterFlag Then
Printer.Print PrintVar
Else
objPrint.Print PrintVar
End If
End Sub
With just a few simple routines like this, you can start to do
generic printing.
Scaling
-------
To accomplish print preview, the program must scale the output to the
picture box to match the output on the printer.
In the example, the PrintStartDoc routine initializes the printer or
picture box and sets up the scaling. The width and height of the paper
are passed to the PrintStartDoc routine. These dimensions are used to
determine the non-printable area of the printer object, find the ratio
of the picture box to the printer, re-size the picture box, and scale
the picture box. The picture box is scaled with the Scale method. After
setting the scale of the picture box, graphic methods use the new
coordinates. For an 8.5 x 11 inch piece of paper the picture box is
scaled with this command:
Picture1.Scale (0, 0)-(8.5, 11)
The Scale method does not scale fonts. To scale the fonts, use the
ratio of the picture box height divided by the printer's height in
inches. Then multiply by this ratio to determine the correct font
size within the picture box. Here is the PrintFontSize routine that
sets the appropriate font sizes in the example:
Sub PrintFontSize (pSize)
If PrinterFlag Then
Printer.FontSize = pSize
Else
'Sized by ratio since Scale method does not effect FontSize
ObjPrint.FontSize = pSize * Ratio
End If
End Sub
The ratio used to calculate the font size can be applied to anything
you need to scale in the picture box that is not automatically scaled
by the Scale method. The ratio is also used in the PrintPicture routine
to scale pictures.
Step-by-Step Example
--------------------
1. Start a new project in Visual Basic. Form1 is created by default.
2. Add a command button (Command1), a check box (Check1), and two
picture boxes (Picture1 and Picture2) to the form.
3. Put the following code in the command button click event:
Sub Command1_Click ()
'Setup (Could be done at design time or in form load)
'Make printing stick
Picture1.AutoRedraw = True
'Add a palette for 256 colors
Picture1.Picture = LoadPicture("C:\VB\PASTEL.DIB")
'Setup hidden picture
Picture2.AutoRedraw = False
Picture2.ScaleMode = 3 'Pixels
Picture2.Visible = False
Picture2.AutoSize = True
Picture2.Picture = LoadPicture("C:\VB\METAFILE\BUSINESS\PRINTER.WMF")
'This print job can go to the printer or the picture box
If Check1.Value = 0 Then PrinterFlag = True
PrintStartDoc Picture1, PrinterFlag, 8.5, 11
'All the subs use inches
PrintBox 1, 1, 6.5, 9
PrintLine 1.1, 2, 7.4, 2
PrintPicture Picture2, 1.1, 1.1, .8, .8
PrintFilledBox 2.1, 1.2, 5.2, .7, RGB(200, 200, 200)
PrintFontName "Arial"
PrintCurrentX 2.3
PrintCurrentY 1.3
PrintFontSize 35
PrintPrint "Visual Basic Printing"
For x = 3 To 5.5 Step .2
PrintCircle x, 3.5, .75
Next
PrintFontName "Courier New"
PrintFontSize 30
PrintCurrentX 1.5
PrintCurrentY 5
PrintPrint "It is possible to do"
PrintFontSize 24
PrintCurrentX 1.5
PrintCurrentY 6.5
PrintPrint "It is possible to do print"
PrintFontSize 18
PrintCurrentX 1.5
PrintCurrentY 8
PrintPrint "It is possible to do print preview"
PrintFontSize 12
PrintCurrentX 1.5
PrintCurrentY 9.5
PrintPrint "It is possible to do print preview with good results."
PrintEndDoc
End Sub
4. Add a new Module to the project (MODULE1.BAS).
5. Put the following code in the basic module:
Option Explicit
' The following Types, Declares, and Constants are only necessary for the
' PrintPicture routine
'=========================================================================
=
Type BITMAPINFOHEADER_TYPE
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
bmiColors As String * 1024
End Type
Type BITMAPINFO_TYPE
BitmapInfoHeader As BITMAPINFOHEADER_TYPE
bmiColors As String * 1024
End Type
'Each of the following declares should be entered on a single line
Declare Function GetDIBits Lib "gdi" (ByVal hDC As Integer,
ByVal hBitmap As Integer, ByVal nStartScan As Integer,
ByVal nNumScans As Integer, ByVal lpBits As Long,
BitmapInfo As BITMAPINFO_TYPE, ByVal wUsage As Integer) As Integer
Declare Function StretchDIBits Lib "gdi" (ByVal hDC As Integer,
ByVal DestX As Integer, ByVal DestY As Integer,
ByVal wDestWidth As Integer, ByVal wDestHeight As Integer,
ByVal SrcX As Integer, ByVal SrcY As Integer,
ByVal wSrcWidth As Integer, ByVal wSrcHeight As Integer,
ByVal lpBits As Long, BitsInfo As BITMAPINFO_TYPE,
ByVal wUsage As Integer, ByVal dwRop As Long) As Integer
Declare Function GlobalAlloc Lib "kernel" (ByVal wFlags As Integer,
ByVal lMem As Long) As Integer
Declare Function GlobalLock Lib "kernel" (ByVal hMem As Integer) As Long
Declare Function GlobalUnlock Lib "kernel"
(ByVal hMem As Integer) As Integer
Declare Function GlobalFree Lib "kernel" (ByVal hMem As Integer) As Intege
r
Global Const SRCCOPY = &HCC0020
Global Const BI_RGB = 0
Global Const DIB_RGB_COLORS = 0
Global Const GMEM_MOVEABLE = 2
'Module level variables set in PrintStartDoc
'Flag indicating Printing or Previewing
Dim PrinterFlag
'Object used for Print Preview
Dim ObjPrint As Control
'Storage for output objects original scale mode
Dim sm
'The size ratio between the actual page and the print preview object
Dim Ratio
'Size of the non-printable area on printer
Dim LRGap
Dim TBGap
'The actual paper size (8.5 x 11 normally)
Dim PgWidth
Dim PgHeight
Sub PrintStartDoc (objToPrintOn As Control, PF, PaperWidth, PaperHeight)
Dim psm
Dim fsm
Dim HeightRatio
Dim WidthRatio
'Set the flag that determines whether printing or previewing
PrinterFlag = PF
'Set the physical page size
PgWidth = PaperWidth
PgHeight = PaperHeight
'Find the size of the non-printable area on the printer
'Will be used to offset coordinates
'These formulas assume the non-printable area is centered on the page
psm = Printer.ScaleMode
Printer.ScaleMode = 5 'Inches
LRGap = (PgWidth - Printer.ScaleWidth) / 2
TBGap = (PgHeight - Printer.ScaleHeight) / 2
Printer.ScaleMode = psm
'Initialize printer or preview object
If PrinterFlag Then
sm = Printer.ScaleMode
Printer.ScaleMode = 5 'Inches
Printer.Print "";
Else
'Set the object used for preview
Set ObjPrint = objToPrintOn
'Scale Object to Printer's printable area in Inches
sm = ObjPrint.ScaleMode
ObjPrint.ScaleMode = 5 'Inches
'Compare the height and with ratios to determine the
'Ratio to use and how to size the picture box
HeightRatio = ObjPrint.ScaleHeight / PgHeight
WidthRatio = ObjPrint.ScaleWidth / PgWidth
If HeightRatio < WidthRatio Then
Ratio = HeightRatio
'Re-size picture box - this does not work on a form
fsm = ObjPrint.Parent.ScaleMode
ObjPrint.Parent.ScaleMode = 5 'Inches
ObjPrint.Width = PgWidth * Ratio
ObjPrint.Parent.ScaleMode = fsm
Else
Ratio = WidthRatio
'Re-size picture box - this does not work on a form
fsm = ObjPrint.Parent.ScaleMode
ObjPrint.Parent.ScaleMode = 5 'Inches
ObjPrint.Height = PgHeight * Ratio
ObjPrint.Parent.ScaleMode = fsm
End If
'Set default properties of picture box to match printer
'There are many that you could add here
ObjPrint.Scale (0, 0)-(PgWidth, PgHeight)
ObjPrint.FontName = Printer.FontName
ObjPrint.FontSize = Printer.FontSize * Ratio
ObjPrint.ForeColor = Printer.ForeColor
ObjPrint.Cls
End If
End Sub
Sub PrintCurrentX (XVal)
If PrinterFlag Then
Printer.CurrentX = XVal - LRGap
Else
ObjPrint.CurrentX = XVal
End If
End Sub
Sub PrintCurrentY (YVal)
If PrinterFlag Then
Printer.CurrentY = YVal - TBGap
Else
ObjPrint.CurrentY = YVal
End If
End Sub
Sub PrintFontName (pFontName)
If PrinterFlag Then
Printer.FontName = pFontName
Else
ObjPrint.FontName = pFontName
End If
End Sub
Sub PrintFontSize (pSize)
If PrinterFlag Then
Printer.FontSize = pSize
Else
'Sized by ratio since Scale method does not effect FontSize
ObjPrint.FontSize = pSize * Ratio
End If
End Sub
Sub PrintPrint (PrintVar)
If PrinterFlag Then
Printer.Print PrintVar
Else
ObjPrint.Print PrintVar
End If
End Sub
Sub PrintLine (bLeft0, bTop0, bLeft1, bTop1)
If PrinterFlag Then
'The following should be entered on a single line
Printer.Line (bLeft0 - LRGap, bTop0 - TBGap)-
(bLeft1 - LRGap, bTop1 - TBGap)
Else
ObjPrint.Line (bLeft0, bTop0)-(bLeft1, bTop1)
End If
End Sub
Sub PrintBox (bLeft, bTop, bWidth, bHeight)
If PrinterFlag Then
'The following should be entered on a single line
Printer.Line (bLeft - LRGap, bTop - TBGap)-
(bLeft + bWidth - LRGap, bTop + bHeight - TBGap), , B
Else
ObjPrint.Line (bLeft, bTop)-(bLeft + bWidth, bTop + bHeight), , B
End If
End Sub
Sub PrintFilledBox (bLeft, bTop, bWidth, bHeight, color)
If PrinterFlag Then
'The following should be entered on a single line
Printer.Line (bLeft - LRGap, bTop - TBGap)-
(bLeft + bWidth - LRGap, bTop + bHeight - TBGap), color, BF
Else
'The following should be entered on a single line
ObjPrint.Line (bLeft, bTop)-(bLeft + bWidth, bTop + bHeight),
color, BF
End If
End Sub
Sub PrintCircle (bLeft, bTop, bRadius)
If PrinterFlag Then
Printer.Circle (bLeft - LRGap, bTop - TBGap), bRadius
Else
ObjPrint.Circle (bLeft, bTop), bRadius
End If
End Sub
Sub PrintNewPage ()
If PrinterFlag Then
Printer.NewPage
Else
ObjPrint.Cls
End If
End Sub
'The following should be entered on a single line
Sub PrintPicture (picSource As Control, ByVal pLeft, ByVal pTop,
ByVal pWidth, ByVal pHeight)
'Picture Box should have autoredraw = False, ScaleMode = Pixel
' Also can have visible=false, Autosize = true
Dim BitmapInfo As BITMAPINFO_TYPE
Dim DesthDC As Integer
Dim hMem As Integer
Dim lpBits As Long
Dim r As Integer
'Precaution
If pLeft < LRGap Or pTop < TBGap Then Exit Sub
If pWidth < 0 Or pHeight < 0 Then Exit Sub
If pWidth + pLeft > PgWidth - LRGap Then Exit Sub
If pHeight + pTop > PgHeight - TBGap Then Exit Sub
picSource.ScaleMode = 3 'Pixels
picSource.AutoRedraw = False
picSource.Visible = False
picSource.AutoSize = True
If PrinterFlag Then
Printer.ScaleMode = 3 'Pixels
'Calculate size in pixels
pLeft = ((pLeft - LRGap) * 1440) / Printer.TwipsPerPixelX
pTop = ((pTop - TBGap) * 1440) / Printer.TwipsPerPixelY
pWidth = (pWidth * 1440) / Printer.TwipsPerPixelX
pHeight = (pHeight * 1440) / Printer.TwipsPerPixelY
Printer.Print "";
DesthDC = Printer.hDC
Else
ObjPrint.Scale
ObjPrint.ScaleMode = 3 'Pixels
'Calculate size in pixels
pLeft = ((pLeft * 1440) / Screen.TwipsPerPixelX) * Ratio
pTop = ((pTop * 1440) / Screen.TwipsPerPixelY) * Ratio
pWidth = ((pWidth * 1440) / Screen.TwipsPerPixelX) * Ratio
pHeight = ((pHeight * 1440) / Screen.TwipsPerPixelY) * Ratio
DesthDC = ObjPrint.hDC
End If
BitmapInfo.BitmapInfoHeader.biSize = 40
BitmapInfo.BitmapInfoHeader.biWidth = picSource.ScaleWidth
BitmapInfo.BitmapInfoHeader.biHeight = picSource.ScaleHeight
BitmapInfo.BitmapInfoHeader.biPlanes = 1
BitmapInfo.BitmapInfoHeader.biBitCount = 8
BitmapInfo.BitmapInfoHeader.biCompression = BI_RGB
'Enter the following on a single line
hMem = GlobalAlloc(GMEM_MOVEABLE, (CLng(picSource.ScaleWidth + 3) \ 4)
*
4 * picSource.ScaleHeight)'DWORD ALIGNED
lpBits = GlobalLock(hMem)
'Enter the following on a single line
r = GetDIBits(picSource.hDC, picSource.Image, 0, picSource.ScaleHeight,
lpBits, BitmapInfo, DIB_RGB_COLORS)
If r <> 0 Then
'Enter the following on a single line
r = StretchDIBits(DesthDC, pLeft, pTop, pWidth, pHeight, 0, 0,
picSource.ScaleWidth, picSource.ScaleHeight, lpBits, BitmapInfo,
DIB_RGB_COLORS, SRCCOPY)
End If
r = GlobalUnlock(hMem)
r = GlobalFree(hMem)
If PrinterFlag Then
Printer.ScaleMode = 5 'Inches
Else
ObjPrint.ScaleMode = 5'Inches
ObjPrint.Scale (0, 0)-(PgWidth, PgHeight)
End If
End Sub
Sub PrintEndDoc ()
If PrinterFlag Then
Printer.EndDoc
Printer.ScaleMode = sm
Else
ObjPrint.ScaleMode = sm
End If
End Sub
6. Save the project.
7. Run it.
Click the command button with the check box checked to preview the
page. Click the command button with the check box cleared to print
the page.
Notes
-----
- The accuracy of the preview really depends on the fonts available.
This method relies upon Windows to return the most appropriate font
and size. You could come up with your own algorythm for choosing a
font size. The TextWidth and TextHeight methods of the Printer
object and picture box may be useful for this.
- The example uses inches the device independent unit of measurement.
But you could use twips, points, millimeters, or centemeters.
- You may want to implement the preview window in a scrollable viewport.
For more information, please see the following article in the Microsoft
Knowledge Base:
ARTICLE-ID: Q71068
TITLE : How to Create Scrollable Viewports in Visual Basic
- There are other methods that you could use to preview printing. You
could pass a device context to a routine that uses only Windows API
functions to draw and print. You could also create a picture that you
either stretch to the printer or to the screen.
Additional reference words: 2.00 3.00
KBCategory: APrg
KBSubcategory: APrgPrint
\*
\* MSINTERNAL:
\* Tested with: HP Laserjet II
\* HP LaserJet III
\* HP LaserJet IIIsi
\* HP LaserJet IIIsi PostScript
\* Compaq QVision 1024*768*256 Lg. Res
\* ATI Graphics Ultra 800*600*256
\* VGA
\* Tech Review: LyleH
================================================================================
Created_by: TIMMCB Edit_review: Edited:
Modified_by: Tech_review: Reviewed: