1. Trang chủ
  2. » Công Nghệ Thông Tin

Visual Basic 2005 Design and Development - Chapter 20 pot

24 259 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Printing
Trường học Standard University
Chuyên ngành Computer Science
Thể loại Chương
Năm xuất bản 2007
Thành phố City Name
Định dạng
Số trang 24
Dung lượng 597,82 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Theform’s Leftand Topproperties give the coordinates of the form’s upper-left corner in screen coordi-nates, so the difference between those values and the translated point gives the dis

Trang 1

Visual Basic NET takes an event-driven approach Here, you start the printing process and thenwait for events APrintDocumentobject raises events and asks you to generate the document’spages The event handler includes a Graphicsobject, and you use its properties and methods todraw whatever output you want to print.

I find this approach rather unnatural, so I also devised a technique that uses metafiles to ment a more intuitive, procedural approach This method lets you draw the entire printout all atonce, rather than responding to events It even lets you go back and modify earlier pages after youhave drawn those that come later For example, it lets you add page numbers of the form “Page 1

imple-of 10” even if you don’t know how many pages there are until after you have generated them.This chapter describes Visual Basic NET’s basic event-driven model It then explains the metafile-based, more intuitive procedural approach

Trang 2

Event-Driven Printing

The basic idea behind event-driven printing is to create a PrintDocumentobject and tell it to start ing Then you respond to the object’s events to generate the pages of printout as the object needs them.The following list describes the object’s key events:

print-❑ BeginPrint— This event occurs when the PrintDocumentobject is about to start printing thedocument The code can use this event to prepare for printing by opening data sources, buildingfonts and brushes, setting a page number variable to 1, and so forth

❑ QueryPageSettings— This event occurs before the PrintDocumentobject starts printing apage It gives the program a chance to change the page’s settings before printing on it Forexample, if you are printing a booklet, you might change the margins on odd and even num-bered pages to allow a gutter on the side where the binding will go

❑ PrintPage— This event occurs when the PrintDocumentobject needs to generate a printedpage The e.Graphicsparameter gives the code a Graphicsobject on which to draw The codeshould set the e.HasMorePagesparameter to Trueif there are more pages to print or Falseifthe program has printed the final page

❑ EndPrint— This event occurs when the PrintDocumentobject is finished printing the lastpage The program should perform cleanup tasks such as shutting down data sources, and dis-posing of fonts and brushes Often, this event handler undoes actions taken in the BeginPrintevent handler

Example program SimplePrint(available for download at www.vb-helper.com/one_on_one.htm)prints and provides a print preview for a very simple document It is stripped down to the bare mini-mum so that you can see how PrintDocumentevents work without becoming distracted by graphicsdetails

The program’s form contains two non-visible components The pdocSimplecomponent is a PrintDocumentobject It provides the events that generate the printout The pviewSimplecontrol is aPrintPreviewDialogcontrol It displays a preview of the printout

The following code shows how the program works:

Public Class Form1

‘ Display a print preview

Private Sub btnPreview_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) Handles btnPreview.Click

‘ Set the print preview control’s PrintDocument object

pviewSimple.Document = pdocSimple

‘ Display the preview

‘ The PrintDocument object does the real work

pviewSimple.ShowDialog()End Sub

Trang 3

End Sub

#Region “Printing Code”

Private m_NextPage As IntegerPrivate m_Font As Font

‘ Prepare to print

Private Sub pdlgWrap_BeginPrint(ByVal sender As Object, _ByVal e As System.Drawing.Printing.PrintEventArgs) _Handles pdocSimple.BeginPrint

‘ Set the next page number

m_NextPage = 1

‘ Create the font we will use

m_Font = New Font(“Times New Roman”, 200, FontStyle.Bold, _GraphicsUnit.Point)

End Sub

‘ Clean up

Private Sub pdocSimple_EndPrint(ByVal sender As Object, _ByVal e As System.Drawing.Printing.PrintEventArgs) _Handles pdocSimple.EndPrint

‘ Dispose of the font

m_Font.Dispose()m_Font = NothingEnd Sub

‘ The PrintDocument needs a page Print the next one

Private Sub pdlgWrap_PrintPage(ByVal sender As System.Object, _ByVal e As System.Drawing.Printing.PrintPageEventArgs) _Handles pdocSimple.PrintPage

‘ Draw the page number

e.Graphics.DrawString(m_NextPage.ToString, _m_Font, Brushes.Black, _

e.MarginBounds.X, e.MarginBounds.Y)m_NextPage += 1

‘ Draw 5 pages

e.HasMorePages = (m_NextPage <= 5)End Sub

#End Region ‘ Printing CodeEnd Class

When you click the Preview button, the program sets the pviewSimplecomponent’s Documenterty to pdocSimple, and then calls the dialog’s ShowDialogmethod The dialog uses the pdocSimpleobject to generate the printout as necessary

prop-When you click the Print button, the program directly calls the pdocSimpleobject’s Printmethod tomake the object immediately generate and print the printout

The printing section of the code includes some module-level variables that control printing and thePrintDocumentobject’s event handlers The m_NextPagevariable tracks the number of the next page toprint The m_Fontvariable stores the font that the printing code uses

Trang 4

When the PrintDocument’s BeginPrintevent fires, the event handler sets m_NextPageto 1and ates a very large font to use when printing.

cre-The PrintDocument’s EndPrintevent handler cleans up by disposing of the font

The PrintPageevent handler contains the most interesting code, although it’s quite simple in thisexample The code uses the e.Graphicsobject’s DrawStringmethod to display the current page num-ber using the large font It then increments the page number and sets e.HasMorePagesto Trueif theprogram has not yet printed five pages

After the PrintPageevent handler exits, the PrintDocumentobject finishes generating the page andraises the event again if e.HasMorePagesindicates that it must print more pages

Figure 20-1 shows the PrintPreviewDialogdisplaying all five of the document’s pages at the same time

Figure 20-1: The PrintPreviewDialogcontrol can display one, two, three,four, or six pages at a time Here the dialog would display six pages, but thedocument has only five

The SimplePrintexample is easy enough to understand because it doesn’t do much Unfortunatelyprinting a less-trivial document can be much more complicated The following sections explain how youcan handle other tasks that are more common and complex

Printing Forms

Visual Basic 6 forms have a PrintFormmethod that immediately sends a bitmapped image of the form tothe printer The result is fairly grainy because the screen resolution is far lower than the printer’s resolu-tion, but this method is so simple that it is used heavily It’s a great way to produce a simple snapshot of aform, or to provide low-resolution printing until you have time to implement a higher-resolution version

Trang 5

Here, “low-resolution” is a relative term A typical monitor might provide between 72 and 130 pixels per inch (PPI) That’s fine for a brightly lighted screen, but printers typically have much higher resolutions ranging from 300 to 1200 dots per inch (DPI) High-end inkjet printers have resolutions up to 9600 DPI The difference in resolution between monitors and printers means that Visual Basic 6’s PrintForm

method draws each screen pixel as a tiny square on the printer The result looks a bit blocky.

Unfortunately, Visual Basic NET’s forms don’t have a PrintFormmethod, so you have to write yourown The first step is to use code similar to the following to get a bitmap representing the form’s image:Module PrintFormCode

‘ Return the form’s image

Public Function GetFormImage(ByVal frm As Form, _ByVal include_borders As Boolean) As Bitmap

‘ Get the whole form

Dim wid, hgt As Integerwid = frm.Width

hgt = frm.HeightDim bm As Bitmap = New Bitmap(wid, hgt)frm.DrawToBitmap(bm, New Rectangle(0, 0, wid, hgt))

‘ If we want the borders, return this bitmap

If include_borders Then Return bm

‘ Make a new bitmap to hold the image without the borders

Dim new_wid As Integer = frm.ClientSize.WidthDim new_hgt As Integer = frm.ClientSize.HeightDim new_bm As New Bitmap(new_wid, new_hgt)Dim new_gr As Graphics = Graphics.FromImage(new_bm)

‘ Get the client area’s origin in screen coordinates

Dim origin As New Point(0, 0)origin = frm.PointToScreen(origin)

‘ See how far this is from the form’s upper left corner

Dim x As Integer = origin.X - frm.LeftDim y As Integer = origin.Y - frm.Top

‘ Copy the form’s client area image into the new bitmap

new_gr.DrawImage(bm, _New RectangleF(0, 0, new_wid, new_hgt), _New RectangleF(x, y, new_wid, new_hgt), _GraphicsUnit.Pixel)

‘ Return the client area image

Return new_bmEnd FunctionEnd ModuleThe code starts by creating a bitmap big enough to hold the form’s image It then calls the form’sDrawToBitmapmethod to make it draw itself into the bitmap If the function’s include_bordersparameter is true, the function returns this bitmap

If the include_bordersparameter is false, the code makes a new bitmap that is the right size to holdthe form’s client area (the area inside the borders) It also makes a Graphicsobject for use when draw-ing on the smaller bitmap

Trang 6

Next, the code makes a Pointobject holding the coordinates of the upper-left corner of the form’s clientarea It uses the form’s PointToScreenmethod to translate that point into screen coordinates Theform’s Leftand Topproperties give the coordinates of the form’s upper-left corner in screen coordi-nates, so the difference between those values and the translated point gives the distance from the upper-left corner of the form to the upper-left corner of its client area.

The code uses those values to copy the part of the form’s image corresponding to the client area into thesmaller bitmap It then returns the result

Example program PrintFormImage(available for download at www.vb-helper.com/one_on_one.htm)uses function GetFormImageto get an image of the form It then displays it in a PrintPreviewDialogorprints it directly Checkboxes enable you to determine whether the program prints the image with orwithout borders, at normal size or scaled to fit the page, and in portrait or landscape orientation

Figure 20-2 shows the program on the left The Print preview dialog on the right displays the form’simage with borders scaled to fill the page in landscape orientation

Program PrintFormImageprepares its PrintDocumentobject and sets the PrintPreviewDialogobject’s Documentproperty the same way program SimplePrintdid in the previous section, “Event-Driven Printing.”

Figure 20-2: Program PrintFormImagecan print an image with or without borders, atnormal size or scaled to fit the page, and in portrait or landscape orientation

The following code shows the PrintDocumentevent handlers that this program uses to display theform’s image:

‘ Set landscape or portrait orientation

Private Sub pdocForm_QueryPageSettings(ByVal sender As Object, _

Trang 7

‘ Print in portrait

e.PageSettings.Landscape = FalseEnd If

End Sub

‘ Print the form’s image

Private Sub pdocForm_PrintPage(ByVal sender As Object, _ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles pdocForm.PrintPage

‘ Get an image of the form

Dim bm As Bitmap = GetFormImage(Me, cboIncludeBorders.Checked)

‘ Prepare the Graphics object

PrepareGraphics(e, bm)

‘ Draw the image at the origin

e.Graphics.DrawImage(bm, 0, 0, bm.Width, bm.Height)

‘ There’s only one page

e.HasMorePages = FalseEnd Sub

‘ Scale and translate the Graphics object appropriately

Private Sub PrepareGraphics(_

ByVal e As System.Drawing.Printing.PrintPageEventArgs, ByVal bm As Bitmap)

‘ See how big the resulting image should be

Dim the_scale As Single

If cboFitPage.Checked Then

‘ Scale to fit

Dim aspect1 As Double = bm.Width / bm.HeightDim aspect2 As Double = e.MarginBounds.Width / e.MarginBounds.Height

If aspect1 > aspect2 Then

‘ The image is relatively wider and thinner than the page

‘ Make it fit the page’s width

the_scale = CSng(e.MarginBounds.Width / bm.Width)Else

‘ The image is relatively shorter and taller than the page

‘ Make it fit the page’s height

the_scale = CSng(e.MarginBounds.Height / bm.Height)End If

‘ Scale

e.Graphics.ScaleTransform(the_scale, the_scale)Else

‘ Use the image at its normal scale

the_scale = 1End If

‘ Translate to center the image

Dim wid As Single = bm.Width * the_scaleDim hgt As Single = bm.Height * the_scaleDim dx As Single = e.MarginBounds.X + (e.MarginBounds.Width - wid) / 2Dim dy As Single = e.MarginBounds.Y + (e.MarginBounds.Height - hgt) / 2e.Graphics.TranslateTransform(dx, dy, Drawing2D.MatrixOrder.Append)End Sub

Trang 8

The QueryPageSettingsevent handler checks the program’s cboLandscapecombo box If the userhas checked this box, the code sets the PageSettingobject’s Landscapeproperty to Trueto make theprinter use a landscape orientation This also adjusts the PrintDocument’s margins so they work withthe landscape setting.

The PrintPageevent handler prints the form’s image It uses function GetFormImageto get a bitmapcontaining the form’s image It then calls subroutine PrepareGraphicsto prepare the Graphicsobject

to display the image properly scaled and centered The routine uses the e.Graphicsobject’s DrawImagemethod to draw the form’s image at the position (0, 0) and sets e.HasMorePagesto Falseto indicatethat there are no more pages

Subroutine PrepareGraphicsstarts by determining how big the form’s image will be

If the Fit Page combo box is checked, it compares the form’s width-to-height ratio with the printedpage’s width-to-height ratio If the form’s ratio is greater than the page’s ratio, the form image is rela-tively wider and shorter than the page, so the program picks a scale factor that makes the image fill thepage horizontally If the form’s ratio is smaller than the page’s ratio, the form image is relatively tallerand thinner than the page, so the program picks a scale factor that makes the image fill the page verti-cally The program then calls the e.Graphicsobject’s ScaleTransformmethod to scale the result.When the program draws on the object, everything is scaled by this amount The result is that the imagewill be scaled to fill the page

After calculating the scale to use, the program determines the image’s final size It then calculates thetranslation it must use to center the scaled image on the form It calls the e.Graphicsobject’s

TranslateTransformmethod to make this translation Now, when the PrintPageevent handlerdraws the image at position (0, 0), the image is scaled appropriately and translated, so it is centered

Wrapping Text

Printing an image of a form is a fairly common task Another everyday task is printing text The

SimplePrintexample earlier in this chapter showed that printing a few numbers or letters is easy.Printing a lot of text that must wrap across pages is harder

Example program PrintWrap, which is available for download at www.vb-helper.com/one_on_one.htm,prints text, wrapping lines at the margins and starting new pages as needed

The program uses the following ParagraphInfoclass to store information about paragraphs that itshould print The class’s FontNumberproperty determines which of three program-defined fonts to usefor each paragraph The Indentproperty gives the amount to increase the paragraph’s left margin.SpaceAfterindicates the amount of vertical space that should be added after the paragraph Finally,the Textproperty gives the paragraph’s text

Public Class ParagraphInfo

Public FontNumber As IntegerPublic Indent As IntegerPublic SpaceAfter As IntegerPublic Text As StringPublic Sub New(ByVal new_FontNumber As Integer, ByVal new_Indent As Integer, _ByVal new_SpaceAfter As Integer, ByVal new_Text As String)

Trang 9

FontNumber = new_FontNumberIndent = new_Indent

SpaceAfter = new_SpaceAfterText = new_Text

End SubEnd ClassThe following code shows the PrintDocument’s BeginPrintand EndPrintevent handlers:

‘ The lines we will print

Private m_Paragraphs As List(Of ParagraphInfo)

‘ The number of the next page we will print

Private m_NextPage As Integer

‘ The distance of the page number from the

‘ top and left edges of the margin area

Private Const PAGE_NUM_MARGIN_X As Integer = 50Private Const PAGE_NUM_MARGIN_Y As Integer = 50

‘ Fonts we use while printing

Private m_Fonts(0 To 2) As Font

‘ Prepare to print

Private Sub pdlgWrap_BeginPrint(ByVal sender As Object, _ByVal e As System.Drawing.Printing.PrintEventArgs) Handles pdocWrapped.BeginPrint

‘ Create the text to print

m_Paragraphs = New List(Of ParagraphInfo)m_Paragraphs.Add(New ParagraphInfo(0, 20, 20, _

“19 Splash Screens”))m_Paragraphs.Add(New ParagraphInfo(1, 0, 20, _

“The first thing a user sees of an application is its splash screen ”)) Other lines omitted

‘ Make the fonts we need

m_Fonts(0) = New Font(“Times New Roman”, 22, FontStyle.Bold, _GraphicsUnit.Point)

m_Fonts(1) = New Font(“Times New Roman”, 14, FontStyle.Regular, _GraphicsUnit.Point)

m_Fonts(2) = New Font(“Courier New”, 10, FontStyle.Regular, _GraphicsUnit.Point)

‘ Set the next page number

m_NextPage = 1End Sub

End Sub

Trang 10

Variable m_Paragraphsholds a list of Paragraphobjects describing the text to print Variablem_NextPagetracks the current page number The m_Fontsarray contains the three fonts that the pro-gram will use to print.

The BeginPrintevent handler adds a series of ParagraphInfoobjects to the m_Paragraphslist Itthen creates three fonts: a large heading font, a smaller text body font, and a code font It sets

m_NextPageto 1and exits

The EndPrintevent handler simply disposes of the fonts

The following code shows the PrintDocument’s PrintPageevent handler:

‘ The PrintDocument needs a page Print the next one

Private Sub pdlgWrap_PrintPage(ByVal sender As System.Object, _

ByVal e As System.Drawing.Printing.PrintPageEventArgs) _

Handles pdocWrapped.PrintPage

‘ Print the page number

Dim x As Single = e.MarginBounds.Right + PAGE_NUM_MARGIN_XDim y As Single = e.MarginBounds.Top - PAGE_NUM_MARGIN_YDim string_format As New StringFormat

string_format.Alignment = StringAlignment.Centerstring_format.LineAlignment = StringAlignment.Centere.Graphics.DrawString(m_NextPage.ToString(), _m_Fonts(1), Brushes.Black, x, y, string_format)m_NextPage += 1

‘ Start at the top

y = e.MarginBounds.Top

‘ Loop while we have paragraphs

Do While m_Paragraphs.Count > 0

‘ Get the next piece of text we need to print

Dim para As ParagraphInfo = m_Paragraphs(0)Dim txt As String = para.Text

‘ See how much room we have

Dim layout_area As New SizeF( _e.MarginBounds.Width - para.Indent, _e.MarginBounds.Bottom - y)

‘ Make the height at least 1 to avoid confusing MeasureString

If layout_area.Height < 1 Then layout_area.Height = 1

‘ See how much of the text will fit

Dim characters_fitted As IntegerDim lines_filled As Integerstring_format.Alignment = StringAlignment.Nearstring_format.LineAlignment = StringAlignment.Nearstring_format.Trimming = StringTrimming.Wordstring_format.FormatFlags = StringFormatFlags.LineLimitDim text_size As SizeF = e.Graphics.MeasureString(txt, _m_Fonts(para.FontNumber), layout_area, string_format, _

Trang 11

characters_fitted, lines_filled)

‘ See if any characters fit

If characters_fitted > 0 Then

‘ Draw the text that fits

Dim layout_rect As New RectangleF( _e.MarginBounds.Left + para.Indent, _

y, _text_size.Width, _text_size.Height)e.Graphics.DrawString(txt, m_Fonts(para.FontNumber), _Brushes.Black, layout_rect, string_format)

‘ Increase y

y += text_size.Height + para.SpaceAfterEnd If

‘ See how much of this paragraph is left

para.Text = para.Text.Substring(characters_fitted)

‘ If all of this paragraph fit, remove it

If para.Text.Length < 1 Then m_Paragraphs.RemoveAt(0)

‘ If we have any text left in the paragraph,

‘ then we have filled this page

‘ End this page and go to the next one

If para.Text.Length > 0 Then Exit DoLoop

‘ See if we have any text left to print

e.HasMorePages = (m_Paragraphs.Count > 0)End Sub

The PrintPageevent handler does the most interesting work It begins by printing the page numberoutside of the page’s margin It uses a StringFormatobject to center the number

The program then sets variable yequal to the top margin This variable keeps track of the upper edge ofthe area that has not yet been printed

The code then enters a loop that continues as long as there are objects in the m_Paragraphslist Thecode gets the paragraph’s text It then builds a SizeFobject to represent the area available for printing.Initially, this is the whole page within the margins, but it shrinks as yincreases

Next, the program uses the e.Graphicsobject’s MeasureStringmethod to see how much of the rent paragraph will fit in the available area It uses a StringFormatobject to indicate that the text will

cur-be printed aligned to the top left of the area, that lines should break at words, and that it should stopwhen no more lines will fit vertically (so that it doesn’t print the top half of a line)

If any characters from the current paragraph fit, the code draws whatever text fits It uses the sameStringFormatobject, so the DrawStringmethod automatically wraps the text across lines and stopswhen it runs out of room The code then increases yto move past the newly printed text

Trang 12

It also adds the paragraph’s SpaceAftervalue to y If the entire paragraph fit in the available area, thenthis is appropriate If some of the paragraph did not fit, then the text goes to the bottom of the page, soadding SpaceAfterto ymoves ypast the bottom margin As you’ll see shortly, that makes the codestart a new page.

The program then removes the printed text from the current paragraph’s text If the paragraph now has

no text, the program removes the paragraph from the m_Paragraphslist

If the current paragraph has any text remaining, the newly printed text must be at the bottom of thepage, so the program exits its Doloop to end the page If the current paragraph has no text, the Doloopcontinues to print the next paragraph

The Doloop ends when the m_Paragraphslist is empty, or when a paragraph reaches the end of the page.The event handler sets e.HasMorePagesto Trueif there are more paragraphs to print, and then exits.Figure 20-3 shows program PrintWrap’s print preview dialog displaying the first three pages of thedocument (You can download this example at www.vb-helper.com/one_on_one.htm.) Though youcan’t read the text, you can see that the first page contains a heading, some body text, a second heading,and more body text The final paragraph continues on the second page The third page contains bodytext, a heading, and some code text that is indented and drawn in a different font

Figure 20-3: Program PrintWrapwraps text across lines and pages

Flowing Text

Program PrintWrapdescribed in the previous section is fairly useful if you only need to display text Acommon task that this program cannot handle is displaying text interspersed with pictures ProgramPrintFlow, shown in Figure 20-4, draws text that flows around pictures

Ngày đăng: 14/08/2014, 11:20