The Windows operating system has always included support for drawing two-dimensional graphics. This support is known as the Graphics Device Interface (GDI) library. The GDI library is now easier to use and provides additional features. The new capabilities are known collectively as GDI+. GDI+ features are exposed in the .NET Framework through classes in the System.Drawing, System.Drawing.Drawing2D, System.Drawing.Imaging, and System.Drawing.Text namespaces. This section discusses some of those capabilities.
Objects of type Graphics (defined in the System.Drawing namespace) represent two-dimensional surfaces on which to draw. A Graphics object must be obtained before any drawing can be done. A common way to obtain a Graphics object is to override the OnPaint method of a form or user control, as shown in the following code fragment:
Public Class MyControl Inherits UserControl Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs) e.Graphics.FillEllipse(New SolidBrush(Me.ForeColor), _ Me.ClientRectangle) End Sub Public Sub New( ) Me.ResizeRedraw = True End Sub End Class
The single argument passed to the OnPaint method,
e
, is of type PaintEventArgs. This class
has a property called Graphics, which holds a reference to the
Graphics object to be used for drawing on the user control or form.
The PaintEventArgs class is defined in the
System.Windows.Forms namespace. It has two
properties:
- ClipRectangle
Defines the area that needs to be drawn. Drawing done outside the limits of the clip rectangle will not be displayed. The coordinates of the rectangle are relative to the client rectangle of the user control or form.
The syntax of the ClipRectangle property is:
Public ReadOnly Property ClipRectangle( ) As System.Drawing.Rectangle
- Graphics
Defines the graphics surface on which to draw. The syntax of the Graphics property is:
Public ReadOnly Property Graphics( ) As System.Drawing.Graphics
The following list shows some of the Graphics class’s many methods that are available for drawing various lines and shapes, and Example 5-7 in Chapter 5 gives an example of drawing a filled ellipse. This list is just to get you started; it is beyond the scope of this book to document the syntax of each of these methods.
- DrawArc
- DrawBezier
Draws a Bezier curve.
- DrawBeziers
Draws a series of Bezier curves.
- DrawClosedCurve
Is the same as the DrawCurve method (see the next item in this list), except that the last point in the curve is connected back to the first point.
- DrawCurve
Draws a smooth, curved figure that passes through a given array of points.
- DrawEllipse
Draws an ellipse.
- DrawIcon
Draws an icon. Icons are represented by objects of type Icon (defined in the System.Drawing namespace). The Icon class defines various methods for loading icons.
- DrawIconUnstretched
Is the same as the DrawIcon method, but does not stretch the icon to fit the clipping rectangle.
- DrawImage
Draws an image. Images are represented by objects of type Image (defined in the System.Drawing namespace). The Image class defines various methods for loading images in standard formats, such as bitmaps and JPEGs.
- DrawImageUnscaled
Is the same as DrawImage, except that the DrawImageUnscaled method ignores any width and height parameters passed to it.
- DrawLine
Draws a line.
- DrawLines
Draws a series of lines.
- DrawPath
Draws a series of lines and curves that are defined by a GraphicsPath object. The GraphicsPath class is beyond the scope of this book.
- DrawPie
Draws a pie section.
- DrawPolygon
Draws lines to connect a series of points.
- DrawRectangle
Draws a rectangle.
- DrawRectangles
Draws a series of rectangles.
- DrawString
Draws text.
- FillClosedCurve
Draws a filled, closed curve.
- FillEllipse
Draws a filled ellipse.
- FillPath
Draws a filled figure whose shape is given by a GraphicsPath object. The GraphicsPath class is beyond the scope of this book.
- FillPie
Draws a filled pie section.
- FillPolygon
Draws a filled polygon (see the DrawPolygon method earlier in this list).
- FillRectangle
Draws a filled rectangle.
- FillRectangles
Draws a series of filled rectangles.
- FillRegion
Draws a filled figure whose shape is given by a Region object.
Pen objects hold the settings used when drawing lines. All of the Graphics class’s Draw...methods (DrawArc, DrawBezier, etc.) require that the caller supply a Pen object. The supplied Pen object determines the properties of the line used for drawing (for example, its color, width, etc.). Example 4-9 shows an OnPaint method that can be used to draw an ellipse on a user control or a form. It is similar to the code in Example 5-6 in Chapter 5, but displays the ellipse a little smaller, and with only a border. The resulting display is shown in Figure 4-9.
Example 4-9. Drawing an ellipse on a form
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs) Dim pn As New Pen(Me.ForeColor) Dim rect As Rectangle rect.X = Me.ClientRectangle.X + (Me.ClientRectangle.Width \ 4) rect.Y = Me.ClientRectangle.Y + (Me.ClientRectangle.Height \ 4) rect.Width = Me.ClientRectangle.Width \ 2 rect.Height = Me.ClientRectangle.Height \ 2 e.Graphics.DrawEllipse(pn, rect) pn.Dispose( ) End Sub
In Example 4-9, the Graphics class’s DrawEllipse method is passed a Pen object, which determines the appearance of the line used for drawing the ellipse, and a rectangle, which defines the shape of the ellipse. The Pen class has four constructors. The constructor used in Example 4-9 takes a parameter of type Color (defined in System.Drawing). The color passed to the Pen class constructor in Example 4-9 is the foreground color of the form (Me.ForeColor). This is a nice touch ensuring that the ellipse will be drawn using whatever color is set as the foreground color of the form on which the ellipse is drawn. See Section 4.6.4 later in this chapter for information on choosing and manipulating colors. Finally, note this line in Example 4-9:
pn.Dispose( )
By convention, objects that allocate scarce resources expose a Dispose method to allow the object client to tell the object to release its resources. When using any object that exposes a Dispose method (as the Pen object does), the Dispose method must be called when the client code is finished using the object. If the Dispose method isn’t called (or if it isn’t implemented), resources will be held longer than necessary, which may in turn result in resources being unavailable for other code that needs them.
The .NET Framework provides a number of predefined pens through the
properties of the Pens and SystemPens classes (defined in the
System.Drawing namespace). For example, the Blue property of the Pens
class returns a Pen object whose color is set to
Color.Blue
. Thus, the following line of code draws
a blue ellipse:
e.Graphics.DrawEllipse(Pens.Blue, rect)
Similarly, the SystemPens class’s WindowText property returns a Pen object whose color is set to the system’s window text color. Using the standard pens provided by the Pens and SystemPens classes can be more efficient than instantiating new Pen objects. However, their properties (such as line width) cannot be altered.
See Table 4-1, later in this chapter, for the list of Pen objects available through the Pens class. See Section 4.6.4.1 in Section 4.6.4 later in this chapter for the list of Pen objects available through the SystemPens class.
When working with a user-instantiated pen, you can modify the line that is drawn by setting properties of the Pen object. The code in Example 4-10 sets the Pen object’s Width property to widen the outline of the ellipse. The lines of code that differ from Example 4-9 are shown in bold. The resulting display is shown in Figure 4-10.
Example 4-10. Setting Pen properties
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs) Dim pn As New Pen(Me.ForeColor)pn.Width = 10
pn.DashStyle = Drawing.Drawing2D.DashStyle.Dash
Dim rect As Rectangle rect.X = Me.ClientRectangle.X + (Me.ClientRectangle.Width \ 4) rect.Y = Me.ClientRectangle.Y + (Me.ClientRectangle.Height \ 4) rect.Width = Me.ClientRectangle.Width \ 2 rect.Height = Me.ClientRectangle.Height \ 2 e.Graphics.DrawEllipse(pn, rect) pn.Dispose( ) End Sub
Example 4-10 sets the Pen object’s Width and DashStyle properties to attain the effect shown in Figure 4-10. The Width property is a value of type Single that determines the width of lines drawn with this pen. The default is 1. The unit of measurement is determined by the PageUnit property of the Graphics object in which the lines are drawn. The PageUnit property is of the enumeration type GraphicsUnit (defined in the System.Drawing namespace). The values of GraphicsUnit that are appropriate for assignment to the PageUnit property are:
-
Display
Units are specified in 1/75 of an inch.
-
Document
Units are specified in 1/300 of an inch.
-
Inch
Units are specified in inches.
-
Millimeter
Units are specified in millimeters.
-
Pixel
Units are specified in pixels.
-
Point
Units are specified in points (1/72 of an inch).
The DashStyle property of the Pen object determines the whether the line is solid or dashed, as well as the style of the dash. The DashStyle property is of the enumeration type DashStyle (defined in the System.Drawing.Drawing2D namespace), which defines the following values:
-
Custom
Specifies a programmer-defined dash style. If this value is used, other properties of the Pen object control the exact appearance of the dashes in the line. Creating custom dash styles is not discussed in this book.
-
Dash
Specifies a dashed line.
-
DashDot
Specifies a line consisting of alternating dashes and dots.
-
DashDotDot
Specifies a line consisting of alternating dashes and two dots.
-
Dot
Specifies a dotted line.
-
Solid
Specifies a solid line.
The standard dash styles are shown in Figure 4-11.
Brush objects hold the settings used when filling graphics areas. All of the Graphics class’s Fill...methods (FillClosedCurve, FillEllipse, etc.) require that the caller supply a Brush object. The supplied Brush object determines how the interior of the figure will be painted. Example 4-11 shows an OnPaint method that can be used to draw an ellipse on a user control or a form. It is similar to Example 4-9, but draws a filled ellipse rather than an outline. The lines that differ from Example 4-9 are shown in bold. The resulting display is shown in Figure 4-12.
Example 4-11. Drawing a filled ellipse on a form
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)Dim br As New SolidBrush(Me.ForeColor)
Dim rect As Rectangle rect.X = Me.ClientRectangle.X + (Me.ClientRectangle.Width \ 4) rect.Y = Me.ClientRectangle.Y + (Me.ClientRectangle.Height \ 4) rect.Width = Me.ClientRectangle.Width \ 2 rect.Height = Me.ClientRectangle.Height \ 2e.Graphics.FillEllipse(br, rect)
br.Dispose( )
End Sub
Note that Example 4-11 is not entirely parallel to Example 4-9. Specifically, Example 4-9 instantiated a Pen object directly, but Example 4-11 instantiates an object from a class that derives from the Brush class rather than directly from the Brush class. Objects can’t be directly instantiated from the Brush class. The classes that derive from Brush are:
- HatchBrush
Fills an area with a hatch pattern. Hatch patterns are patterns of lines and spaces. The HatchBrush class’s HatchStyle property determines the exact pattern of the hatch. It is defined in the System.Drawing.Drawing2D namespace.
- LinearGradientBrush
Fills an area with a gradient blend of two or more colors. It is defined in the System.Drawing.Drawing2D namespace.
- PathGradientBrush
Fills the internal area of a GraphicsPath object with a gradient blend of two or more colors. It is defined in the System.Drawing.Drawing2D namespace.
- SolidBrush
Fills an area with a solid color. It is defined in the System.Drawing namespace.
- TextureBrush
Fills an area with an image. It is defined in the System.Drawing namespace.
The .NET Framework provides a number of predefined brushes through the properties of the Brushes and SystemBrushes classes (defined in the System.Drawing namespace). For example, the Blue property of the Brushes class returns a Brush object that fills areas with solid blue. Thus, the following line of code draws a solid blue ellipse:
e.Graphics.FillEllipse(Brushes.Blue, rect)
Similarly, the SystemBrushes class’s Window property returns a Brush object whose color is set to the background color of the system’s window client area. Using the standard brushes provided by the Brushes and SystemBrushes classes can be more efficient than instantiating new Brush objects. However, their properties cannot be altered.
See Table 4-1 for the list of Brush objects available through the Brushes class. See Section 4.6.4.1 for the list of Brush objects available through the SystemBrushes class.
Colors
are represented by values of type Color. The Color structure defines
141 named colors and exposes them as shared read-only properties
whose values are of type Color. They serve the purpose of color
constants. For example, the following code fragment sets the
background color of the form frm
to white:
frm.BackColor = Color.White
The color properties exposed by the Color structure have the same names as the pen properties exposed by the Pens class and the brush properties exposed by the Brushes class. The list is lengthy, so it is printed here only once, in Table 4-1.
Table 4-1. Properties common to the Color, Pens, and Brushes classes
AliceBlue |
AntiqueWhite |
Aqua |
Aquamarine |
Azure |
Beige |
Bisque |
Black |
BlanchedAlmond |
Blue |
BlueViolet |
Brown |
BurlyWood |
CadetBlue |
Chartreuse |
Chocolate |
Coral |
CornflowerBlue |
Cornsilk |
Crimson |
Cyan |
DarkBlue |
DarkCyan |
DarkGoldenrod |
DarkGray |
DarkGreen |
DarkKhaki |
DarkMagenta |
DarkOliveGreen |
DarkOrange |
DarkOrchid |
DarkRed |
DarkSalmon |
DarkSeaGreen |
DarkSlateBlue |
DarkSlateGray |
DarkTurquoise |
DarkViolet |
DeepPink |
DeepSkyBlue |
DimGray |
DodgerBlue |
Firebrick |
FloralWhite |
ForestGreen |
Fuchsia |
Gainsboro |
GhostWhite |
Gold |
Goldenrod |
Gray |
Green |
GreenYellow |
Honeydew |
HotPink |
IndianRed |
Indigo |
Ivory |
Khaki |
Lavender |
LavenderBlush |
LawnGreen |
LemonChiffon |
LightBlue |
LightCoral |
LightCyan |
LightGoldenrodYellow |
LightGray |
LightGreen |
LightPink |
LightSalmon |
LightSeaGreen |
LightSkyBlue |
LightSlateGray |
LightSteelBlue |
LightYellow |
Lime |
LimeGreen |
Linen |
Magenta |
Maroon |
MediumAquamarine |
MediumBlue |
MediumOrchid |
MediumPurple |
MediumSeaGreen |
MediumSlateBlue |
MediumSpringGreen |
MediumTurquoise |
MediumVioletRed |
MidnightBlue |
MintCream |
MistyRose |
Moccasin |
NavajoWhite |
Navy |
OldLace |
Olive |
OliveDrab |
Orange |
OrangeRed |
Orchid |
PaleGoldenrod |
PaleGreen |
PaleTurquoise |
PaleVioletRed |
PapayaWhip |
PeachPuff |
Peru |
Pink |
Plum |
PowderBlue |
Purple |
Red |
RosyBrown |
RoyalBlue |
SaddleBrown |
Salmon |
SandyBrown |
SeaGreen |
SeaShell |
Sienna |
Silver |
SkyBlue |
SlateBlue |
SlateGray |
Snow |
SpringGreen |
SteelBlue |
Tan |
Teal |
Thistle |
Tomato |
Transparent |
Turquoise |
Violet |
Wheat |
White |
WhiteSmoke |
Yellow |
YellowGreen |
It is useful to discover the colors that Windows uses to draw specific window elements, such as the active window’s title bar. If the color itself is required, it can be obtained from the SystemColors class. If a pen or brush of the appropriate color is needed, the pen or brush can be obtained from the corresponding property of the Pens or Brushes class, respectively. The property names exposed by these three classes overlap and, therefore, are presented here in a single list:
- ActiveBorder
The color of the filled area of the border of the active window. (Not available on the Pens class.)
- ActiveCaption
The background color of the title bar of the active window. (Not available on the Pens class.)
- ActiveCaptionText
The text color in the title bar of the active window.
- AppWorkspace
The background color of MDI parent windows. (Not available on the Pens class.)
- Control
The background color of controls.
- ControlDark
The shadow color of controls (for 3-D effects).
- ControlDarkDark
The very dark shadow color of controls (for 3-D effects).
- ControlLight
The highlight color of controls (for 3-D effects).
- ControlLightLight
The very light highlight color of controls (for 3-D effects).
- ControlText
The color of text on controls.
- Desktop
The color of the Windows desktop. (Not available on the Pens class.)
- GrayText
The text color of disabled controls or other disabled visual elements. (Not available on the Brushes class.)
- Highlight
The background color of highlighted (selected) text.
- HighlightText
The text color of highlighted (selected) text.
- HotTrack
The background color of a hot tracked item. Hot tracking is highlighting an item as the mouse moves over it. Windows menus use hot tracking. (Not available on the Pens class.)
- InactiveBorder
The color of the filled areas of the borders of inactive windows. (Not available on the Pens class.)
- InactiveCaption
The background color of the title bars of inactive windows. (Not available on the Pens class.)
- InactiveCaptionText
The text color in the title bars of inactive windows. (Not available on the Brushes class.)
- Info
The background color of tool tips. (Not available on the Pens class.)
- InfoText
The text color of tool tips. (Not available on the Brushes class.)
- Menu
The background color of menus. (Not available on the Pens class.)
- MenuText
The text color of menus. (Not available on the Brushes class.)
- ScrollBar
The color of scroll bars in the area not occupied by the scroll box (or thumb). (Not available on the Pens class.)
- Window
The background color of the client areas of windows. (Not available on the Pens class.)
- WindowFrame
The color of the frames surrounding windows. (Not available on the Brushes class.)
- WindowText
The color of the text in the client areas of windows.
Note that some of these properties aren’t available on either the Pens class or the Brushes class. In such cases, it is still possible to get a Pen or Brush object of the appropriate color by instantiating a new Pen or Brush object, passing to its constructor the desired color value, like this:
Dim br As New SolidBrush(SystemColors.InfoText)
Alpha blending is a process that allows a Graphics object to appear transparent, causing Graphics objects beneath it to be seen through the object. The degree of transparency can be controlled in steps from completely transparent (invisible) to completely opaque (obscuring any objects beneath it). To draw a transparent object, instantiate Pen and Brush objects having colors whose alpha component is less than the maximum value of 255. A color’s alpha component is given by the A property of the Color structure. This property is a Byte, so it can take values from 0 (invisible) to 255 (completely opaque).
Example 4-12 shows an OnPaint method that draws text and then draws two overlapping, transparent ellipses in the same space as the text. Normally, the ellipses would obscure the text, and the second ellipse would obscure the first. In this case, however, the text can be seen through the ellipses because the ellipses are transparent, and the first ellipse can be seen through the second. The result is shown in Figure 4-13.
Example 4-12. Drawing transparent figures
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs) ' Determine the text to display and its font. Dim str As String = "Here is some text to display in a form." Dim fnt As New Font("Arial", 10, FontStyle.Regular, GraphicsUnit.Point) ' Determine the X and Y coordinates at which to draw the text so ' that it is centered in the window. Dim szf As SizeF = e.Graphics.MeasureString(str, fnt) Dim xText As Single = (Me.DisplayRectangle.Width - szf.Width) / 2 Dim yText As Single = (Me.DisplayRectangle.Height - szf.Height) / 2 ' Draw the text. e.Graphics.DrawString(str, fnt, Brushes.Black, xText, yText) ' Create a blue brush that is mostly transparent. Dim br As New SolidBrush(Color.FromArgb(160, Color.Blue)) ' Determine the bounding rectangle for the first ellipse. Dim rect As Rectangle rect.X = Me.DisplayRectangle.X + (Me.DisplayRectangle.Width \ 8) rect.Y = Me.DisplayRectangle.Y + (Me.DisplayRectangle.Height \ 8) rect.Width = Me.DisplayRectangle.Width \ 2 rect.Height = Me.DisplayRectangle.Height \ 2 ' Draw the first ellipse. e.Graphics.FillEllipse(br, rect) ' Release the brush. br.Dispose( ) ' Create a red brush that is mostly transparent. br = New SolidBrush(Color.FromArgb(160, Color.Red)) ' Determine the bounding rectangle for the second ellipse. rect.X += (Me.DisplayRectangle.Width \ 4) rect.Y += (Me.DisplayRectangle.Height \ 4) ' Draw the second ellipse. e.Graphics.FillEllipse(br, rect) ' Release the brush. br.Dispose( ) End Sub
Antialiasing
is a technique for making the edges of graphics figures appear less
jagged. To turn on antialiasing, set the Graphics object’s
SmoothingMode property to SmoothingMode.AntiAlias
.
(SmoothingMode is an enumeration defined in the
System.Drawing.Drawing2D namespace.) Compare the arcs shown in Figure 4-14. Both arcs were drawn by calling the DrawArc
method of the Graphics class, but the arc on the left was drawn with
the SmoothingMode property set to
SmoothingMode.None
(the default), and the arc on
the right was drawn with the SmoothingMode property set to
SmoothingMode.AntiAlias
. Figure 4-15 shows a close-up comparison view of the upper
portion of both arcs.
As Figure 4-15 shows, antialiasing appears to improve pixel resolution by using gradient shades of the color being rendered and of the background color (in this case, black and white, respectively).
The downside to antialiasing is that it takes more time to render.
Get Programming Visual Basic .NET now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.