As nifty as all the built-in controls are and as nicely as you can arrange them on forms using the Designer, user controls, and dialogs, sometimes you need to take things into your own hands and render the state of your form or control yourself. For example, if you need to compose a fancy About box, as shown in Figure 1.17, you'll need to handle the form's Paint event and do the drawing yourself. Figure 1.17. Custom Drawing (See Plate 3)
The following is the Paint event-handling code to fill the inside of the About box: Private Sub AboutDialog_Paint(sender As Object, _ e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint Dim g As Graphics = e.Graphics g.SmoothingMode = SmoothingMode.AntiAlias Dim rect As Rectangle = Me.ClientRectangle Dim cx As Integer = rect.Width Dim cy As Integer = rect.Height Dim scale As Single = CSng(cy) / CSng(cx) Dim brush As LinearGradientBrush = _ New LinearGradientBrush(Me.ClientRectangle, _ Color.Empty, Color.Empty, 45) Dim blend As ColorBlend = New ColorBlend() blend.Colors = New Color() {Color.Red, Color.Green, Color.Blue} blend.Positions = New Single() {0, 0.5, 1} brush.InterpolationColors = blend Dim pen As Pen = New Pen(brush) Dim x As Integer For x = 0 To cx Step 7 g.DrawLine(pen, 0, x * scale, cx - x, 0) g.DrawLine(pen, 0, (cx - x) * scale, cx - x, cx * scale) g.DrawLine(pen, cx - x, 0 * scale, cx, (cx - x) * scale) g.DrawLine(pen, cx - x, cx * scale, cx, x * scale) Next Dim format As StringFormat = New StringFormat() format.Alignment = StringAlignment.Center format.LineAlignment = StringAlignment.Center Dim s As String = "Ain't graphics cool?" g.DrawString(s, Me.Font, brush, rect, format) End Sub Notice the use of the Graphics object from the PaintEventArgs passed to the event handler. This provides an abstraction around the specific device we're drawing on. If we'd like to print instead, it's a matter of getting at another Graphics object that models the printer. We can do that using the PrintDocument component and handling the events that it fires when the user requests a document to be printed. For example, we can drag the PrintDocument component from the Toolbox onto our AboutDialog form and use it to implement a Print button: Sub printButton_Click(sender As Object, e As EventArgs) _ Handles printButton.Click Dim dlg As PrintDialog = New PrintDialog() dlg.Document = PrintDocument1 If dlg.ShowDialog() = DialogResult.OK Then PrintDocument1.Print() End If End Sub Notice that before we ask the PrintDocument component to print, we use the standard PrintDialog component to ask the user which printer to use. If the user presses the OK button, we ask the document to print. Of course, it can't print on its own. Instead, it will fire the PrintPage event, asking us to draw each page: Imports System.Drawing.Printing ... Private Sub printDocument1_PrintPage(sender As Object, _ e as PrintPageEventArgs) Handles printDocument1.PrintPage ... End Sub If you'd like to print more than one page, set the HasMorePages property of the PrintPageEventArgs class until all pages have been printed. If you'd like to be notified at the beginning and end of each print request as a whole, you'll want to handle the BeginPrint and EndPrint events. If you'd like to change settings, such as margins, paper size, landscape versus portrait mode, and so on, you'll want to handle the QueryPageSettings event. After you have the PrintDocument events handled, WinForms makes adding print preview as easy as using the PrintPreview dialog: Sub printPreviewButton_Click(sender As Object, e As EventArgs) _ Handles printPreviewButton.Click printPreviewDialog.Document = printDocument1 printPreviewDialog.ShowDialog() End Sub For more details of the printing and the drawing primitives used to render state onto a Graphics object, you'll want to read Chapter 4: Drawing Basics and Chapter 7: Printing. |